find
を取得して、シェルで定義した関数を実行する方法はありますか?例えば:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} \;
その結果は次のとおりです。
find: dosomething: No such file or directory
find
の-exec
を取得してdosomething
を表示する方法はありますか?
シェルのみがシェル関数の実行方法を知っているため、関数を実行するにはシェルを実行する必要があります。また、関数をexport -f
でエクスポート用にマークする必要があります。そうしないと、サブシェルはそれらを継承しません。
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
find . | while read file; do dosomething "$file"; done
上記のJakの答えは素晴らしいですが、簡単に克服できるいくつかの落とし穴があります。
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
これは、改行の代わりにヌルを区切り文字として使用するため、改行付きのファイル名が機能します。また、-r
フラグを使用して、バックスラッシュのエスケープを無効にします。ファイル名にバックスラッシュを使用しないと機能しません。また、IFS
をクリアして、名前の末尾の空白が破棄されないようにします。
以下に示すように、{}
に引用符を追加します。
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
これにより、find
によって返される特殊文字に起因するエラーが修正されます。たとえば、名前に括弧が含まれるファイルなどです。
効率を上げるために、多くの人がxargs
を使用して結果をまとめて処理しますが、非常に危険です。そのため、結果を一括で実行するfind
に導入された代替メソッドがありました。
ただし、このメソッドには、たとえばPOSIX -find
でコマンドの最後に{}
を含める必要があるなど、いくつかの注意事項があることに注意してください。
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
は、多くの結果を引数としてbash
の1回の呼び出しに渡し、for
ループはそれらの引数を反復処理し、それぞれの関数でdosomething
を実行します。
上記のソリューションは、$1
から引数を開始するため、_
($0
を表す)があります。
同様に、受け入れられたトップアンサーは次のように修正されるべきだと思います
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
引数は常に$1
で始まる必要があるため、これはより健全なだけでなく、find
によって返されるファイル名がシェルにとって特別な意味を持つ場合、$0
を使用すると予期しない動作につながる可能性があります。
スクリプトを呼び出して、見つかった各アイテムを引数として渡します。
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
スクリプトを単独で実行すると、探しているものが検出され、各検索結果が引数として渡されて自分自身が呼び出されます。引数を指定してスクリプトを実行すると、引数でコマンドが実行されて終了します。
現在のディレクトリ内のすべてのファイルで特定のコマンドを実行するbash関数を探している人のために、上記の回答から1つをコンパイルしました。
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
スペースを含むファイル名で中断することに注意してください(以下を参照)。
例として、次の関数を使用します。
world(){
sed -i 's_hello_world_g' "$1"
}
現在のディレクトリのすべてのファイルで、helloのすべてのインスタンスをworldに変更したいとします。私はやります:
toall world
ファイル名の記号を安全に使用するには、次を使用します。
toall(){
find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}
(ただし、-print0
を処理するfind
が必要です(例:GNU find
)。
私は次のように簡単な方法を見つけます、単一のdoで2つのコマンドを繰り返す
func_one () {
echo "first thing with $1"
}
func_two () {
echo "second thing with $1"
}
find . -type f | while read file; do func_one $file; func_two $file; done
functionをそのように実行することはできません。
これを克服するには、シェルスクリプトに関数を配置し、find
から呼び出すことができます
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
次に、findで次のように使用します。
find . -exec dosomething.sh {} \;
関数を別のファイルに入れ、find
を取得して実行します。
シェル関数は、定義されているシェルの内部にあります。 find
はそれらを見ることができません。
参考までに、私はこのシナリオを次の方法で回避します。
for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
_script_function_call $i;
done;
現在のスクリプトファイルで検索の出力を取得し、必要に応じて出力を繰り返します。私は受け入れられた答えに同意しますが、スクリプトファイルの外部に関数を公開したくありません。
直接ではありませんFindは、シェルではなく、別のプロセスで実行されます。
関数と同じジョブを実行するシェルスクリプトを作成し、-exec
それを見つけることができます。