如何在 exec 和 find 中使用正则表达式?

如何在 exec 和 find 中使用正则表达式?

是否可以根据参数内的结果(文件名)使用正则exec表达式find?我希望能够根据部分参数“执行”,例如:

find . -name pattern -regex "foo (regex1) bar (Regex2)" -exec something $1 $2 ;

答案1

您不能在要执行的命令中使用正则表达式中的捕获组。如果您使用find -regex限制匹配,则必须在命令中进行一些额外的匹配。您可以通过调用 shell 并使用其自己的模式匹配结构来做到这一点。例如,如果foobar是常量字符串并且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 模式regex1regex2但是,对于该特定形式的路径,请匹配相同的部分。如果foobar无法用普通 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

相关内容