パラメータ内で結果(ファイル名)に基づいて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