在 grep 正则表达式中匹配 X 或 Y

Match X or Y in grep regular expression

我正在尝试 运行 一个相当简单的正则表达式来清除一些主目录。对于背景:我试图要求我系统上的用户清除他们不需要的文件以清除他们主目录中的 space,所以我想用脚本通知用户,例如 Anaconda / Miniconda 安装脚本,他们可以清除它。

为了生成可能需要此类电子邮件的用户列表,我正在尝试 运行 一个简单的正则表达式来列出包含此类安装脚本的所有主目录。所以我的假设是以下内容就足够了:

for d in $(ls -d /home/); do
    if $(ls $d | grep -q "(Ana|Mini)conda[23].*\.sh"); then
        echo $d;
    fi;
done;

但是在 运行 这样做之后,遗憾的是,结果一无所获。看了一会儿,我注意到 grep 并不像我期望的那样解释正则表达式。以下:

echo "Lorem ipsum dolor sit amet" | grep "(Lorem|Ipsum) ipsum"

结果完全没有匹配项。这就解释了为什么上面的 forloop 也不起作用。

那么我的问题是:是否可以匹配指定的正则表达式 (Ana|Mini)conda[23].*\.sh,就像它匹配 https://regex101.com/r/yxN61p/1 中的字符串一样?或者是否有其他方法可以在 bash?

中使用简单的 for 循环找到所有在主目录中拥有此类文件的用户

简短回答:grep 默认为基本正则表达式 (BRE),但未转义的 ()| 是扩展正则表达式 (ERE) 的一部分。 GNU grep,作为一个扩展,支持交替(这在技术上不是 BRE 的一部分),但是你必须转义 \:

grep -q "\(Ana\|Mini\)conda[23].*\.sh"

或者您可以表明要使用 ERE:

grep -Eq "(Ana|Mini)conda[23].*\.sh"

更长的答案:说了这么多,你不需要 grep,解析 ls 的输出会带来很多 pitfalls。相反,您可以使用 globs:

printf '%s\n' /home/*/*{Ana,Mini}conda[23]*.sh

如果我理解正确的话,应该这样做。

这利用了这样一个事实,即如果提供的参数多于格式化指令,printf 只会重复其格式化字符串,并在单独的行上打印每个文件。

/home/*/*{Ana,Mini}conda[23]*.sh 使用 brace expansion,即它首先扩展为

/home/*/*Anaconda[23]*.sh /home/*/*Miniconda[23]*.sh

然后每一个都用 filename expansion 扩展。 [23] 的工作方式与正则表达式相同; * 是“除 / 之外的任何字符的零个或多个”。

如果您不知道要查找的文件在目录树中有多深,您可以使用 globstar**:

shopt -s globstar
printf '%s\n' /home/**/*{Ana,Mini}conda[23]*.sh

** 匹配所有文件和零个或多个子目录。

最后,如果您想处理没有匹配的情况,您可以设置 shopt -s nullglob(如果没有匹配则展开为空)或 shopt -s failglob(如果没有匹配则错误)。

Shell 模式描述 here

您根本不需要 lsgrep

shopt -s extglob

for f in /home/*/@(Ana|Mini)conda[23].*.sh; do
  echo "$f"
done

启用 extglob 后,@(Ana|Mini) 匹配 AnaMini