execとfindで正規表現を使用する方法は?

execとfindで正規表現を使用する方法は?

パラメータ内で結果(ファイル名)に基づいてexec正規表現を使用できますかfind?たとえば、次のようないくつかのパラメータに基づいて「実行」できるようにしたいとします。

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

答え1

実行するコマンドの正規表現には、キャプチャリンググループを使用できません。制限付き一致を使用する場合は、find -regexコマンドでいくつかの追加の一致を実行する必要があります。シェルを呼び出し、独自のパターンマッチング構文を使用してこれを実行できます。たとえば、fooおよびbarが定数文字列で、次のようにregex1一致できない場合bar

find … -exec sh -c '
  x=${0#foo}
  y=${x#*bar}
  x=${x%%bar*}
  something "$x" "$y"
' {} \;

シェルを呼び出すと、わずかなオーバーヘッドが発生します。シェルを一括で呼び出すと、パフォーマンスがわずかに向上する可能性があります。

find … -exec sh -c '
  for item do
    item=${item#foo}
    y=${item#*bar}
    x=${item%%bar*}
    something "$x" "$y"
  done
' sh {} +

regex1いくつかのフィルタリングが行われたため、およびを超える一致するシェルパターンに移動できますが、特定のパスregex2形式では同じ部分と一致します。通常のシェルパターンでfooおよびを表現できない場合は、正規表現と同じbarくらい強力な追加パターンである、、、およびをサポートするkshまたはbashを@(alter|native)呼び出す*(zero-or-more)ことができます+(one-or-more)?(optional)!(negated)バッシュから、これらのモードを有効にする必要があります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呼び出しプログラムを呼び出します。最初と2番目の引数を連続語でソートして実行しますxargs -n 2。 xargsの奇妙な引用形式を避けるために、ヌルバイトを区切り文字として使用するか、-d '\n'厳密な行固有の解析を使用してください。 sed などの最新の GNU ツールでは、レコードを区切るために改行文字の代わりにヌルバイトを使用できます。

find … -print0 |
sed -z 's/^foo\(regex1\)bar\(regex2\)$/\1\x00\2/'
| xargs -n2 -0 something

別のアプローチは、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

関連情報