是否可以根据参数内的结果(文件名)使用正则exec
表达式find
?我希望能够根据部分参数“执行”,例如:
find . -name pattern -regex "foo (regex1) bar (Regex2)" -exec something $1 $2 ;
答案1
您不能在要执行的命令中使用正则表达式中的捕获组。如果您使用find -regex
限制匹配,则必须在命令中进行一些额外的匹配。您可以通过调用 shell 并使用其自己的模式匹配结构来做到这一点。例如,如果foo
和bar
是常量字符串并且regex1
不能匹配bar
:
find … -exec sh -c '
x=${0#foo}
y=${x#*bar}
x=${x%%bar*}
something "$x" "$y"
' {} \;
调用 shell 会产生一些开销。通过批量调用 shell 可以稍微提高性能。
find … -exec sh -c '
for item do
item=${item#foo}
y=${item#*bar}
x=${item%%bar*}
something "$x" "$y"
done
' sh {} +
由于您已经完成了一些过滤,因此您可能能够摆脱匹配超过 和 的 shell 模式regex1
,regex2
但是,对于该特定形式的路径,请匹配相同的部分。如果foo
和bar
无法用普通 shell 模式表达,您可以调用 ksh 或 bash,它们支持与正则表达式一样强大的额外模式:@(alter|native)
、*(zero-or-more)
、+(one-or-more)
、?(optional)
和!(negated)
。在bash中,这些模式需要启用shopt -s extglob
。在 ksh 中,它们是本地可用的。
在 bash 中,有一个正则表达式匹配结构,您可以使用它条件句: [[ $STRING =~ REGEXP ]]
。正则表达式是一个 ERE(如find -regextype posix-egrep
)。 (Zsh 有类似的;ksh 有=~
但不公开捕获组。)捕获组可通过BASH_REMATCH
数组获得。
find … -exec bash -c '
for item do
[[ item =~ foo(regex1)bar(regex2) ]]
something "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
done
' bash {} +
另一种方法是打印结果并过滤,然后调用xargs
调用该程序。将第一个和第二个参数安排为连续项并运行xargs -n 2
。使用空字节作为分隔符以避免 xargs 奇怪的引用格式,或者使用-d '\n'
严格的逐行解析。最近的 GNU 工具(例如 sed)可以使用空字节而不是换行符来分隔记录。
find … -print0 |
sed -z 's/^foo\(regex1\)bar\(regex2\)$/\1\x00\2/'
| xargs -n2 -0 something
另一种方法是放弃 find 并使用 ksh93、bash 或 zsh 的递归通配符功能:**/
递归匹配子目录。这对于涉及布尔连接器的复杂查找表达式来说是不可能的,但对于大多数情况来说已经足够了。例如,在 bash 中(请注意,这会递归到目录的符号链接,例如find -L
):
shopt -s extglob globstar
for x in **/*bar*; do
if [[ item =~ foo(regex1)bar(regex2) ]]; then
something "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
fi
done
在 zsh 中:
for x in **/*bar*; do
if [[ item =~ foo(regex1)bar(regex2) ]]; then
something $match[1] $match[2]
fi
done