find 命令不能排除确切的正则表达式

find command can't exclude the exact regex

我有以下脚本:

#!/bin/bash
arg=
exclude='(/etc/alternatives/(awk|vim)|/usr/sbin/poweroff)$'
find $arg -type f,l,c,b -regextype posix-extended -not -regex "${exclude}" -print

我没有在每个文件的开头使用 ^,因此它可以以任何内容开头。但是我在每个文件的末尾都使用了$

因此,当我 运行 脚本以这种方式正常工作时:

$ sudo bash script.sh /etc/ | grep awk
/etc/alternatives/nawk
/etc/alternatives/nawk.1.gz
/etc/alternatives/awk.1.gz

但是当我这样做时是错误的:

$ sudo cp -rv /etc/ /tmp/
$ sudo bash script.sh /tmp/etc/ | grep awk
/tmp/etc/alternatives/awk
/tmp/etc/alternatives/nawk
/tmp/etc/alternatives/nawk.1.gz
/tmp/etc/alternatives/awk.1.gz

这里您看到文件 /tmp/etc/alternatives/awk 由于缺少 ^ 符号而不应在结果中传递。

更新

这个模式很好用,但我想使用上面的模式:

find $arg -type f,l,c,b | grep -Ev "${exclude}"

据我所知,-regex 测试是特定于 GNU 的 find 实现的功能;它不是由 POSIX 定义的。 GNU 的实现无论如何几乎肯定是您会在您最喜欢的 Linux 发行版中找到的那个。 Its manual 有话要说:

Test: -regex expr
Test: -iregex expr
True if the entire file name matches regular expression expr. This is a match on the whole path, not a search. [...]

(强调)。也就是说,即使在模式中没有明确的锚点,测试也总是像正则表达式锚定到行的开始端一样执行。您可以通过在正则表达式前添加前缀和/或后缀 .* 来解决这个问题。

对于您的示例,可能如下所示:

exclude='.*(/etc/alternatives/(awk|vim)|/usr/sbin/poweroff)'

我省略了不需要的尾随锚点,因为这对我来说似乎更清楚,但如果你想保留它,那就这样做——它没有害处。