web-dev-qa-db-ja.com

Linuxでシェル機能を見つけますか?

findを取得して、シェルで定義した関数を実行する方法はありますか?例えば:

dosomething () {
  echo "doing something with $1"
}
find . -exec dosomething {} \;

その結果は次のとおりです。

find: dosomething: No such file or directory

find-execを取得してdosomethingを表示する方法はありますか?

166
alxndr

シェルのみがシェル関数の実行方法を知っているため、関数を実行するにはシェルを実行する必要があります。また、関数をexport -fでエクスポート用にマークする必要があります。そうしないと、サブシェルはそれらを継承しません。

export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
234
Adam Rosenfield
find . | while read file; do dosomething "$file"; done
103
Jac

上記のJakの答えは素晴らしいですが、簡単に克服できるいくつかの落とし穴があります。

find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done

これは、改行の代わりにヌルを区切り文字として使用するため、改行付きのファイル名が機能します。また、-rフラグを使用して、バックスラッシュのエスケープを無効にします。ファイル名にバックスラッシュを使用しないと機能しません。また、IFSをクリアして、名前の末尾の空白が破棄されないようにします。

18
pajamian

以下に示すように、{}に引用符を追加します。

export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;

これにより、findによって返される特殊文字に起因するエラーが修正されます。たとえば、名前に括弧が含まれるファイルなどです。

18
Wagner

一括処理結果

効率を上げるために、多くの人がxargsを使用して結果をまとめて処理しますが、非常に危険です。そのため、結果を一括で実行するfindに導入された代替メソッドがありました。

ただし、このメソッドには、たとえばPOSIX -findでコマンドの最後に{}を含める必要があるなど、いくつかの注意事項があることに注意してください。

export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +

findは、多くの結果を引数としてbashの1回の呼び出しに渡し、forループはそれらの引数を反復処理し、それぞれの関数でdosomethingを実行します。

上記のソリューションは、$1から引数を開始するため、_$0を表す)があります。

結果を1つずつ処理する

同様に、受け入れられたトップアンサーは次のように修正されるべきだと思います

export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;

引数は常に$1で始まる必要があるため、これはより健全なだけでなく、findによって返されるファイル名がシェルにとって特別な意味を持つ場合、$0を使用すると予期しない動作につながる可能性があります。

8
Dominik

スクリプトを呼び出して、見つかった各アイテムを引数として渡します。

#!/bin/bash

if [ ! $1 == "" ] ; then
   echo "doing something with $1"
   exit 0
fi

find . -exec $0 {} \;

exit 0

スクリプトを単独で実行すると、探しているものが検出され、各検索結果が引数として渡されて自分自身が呼び出されます。引数を指定してスクリプトを実行すると、引数でコマンドが実行されて終了します。

8
Mike Maready

現在のディレクトリ内のすべてのファイルで特定のコマンドを実行する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)。

3
Jason Basanese

私は次のように簡単な方法を見つけます、単一の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
2
edib

functionをそのように実行することはできません。

これを克服するには、シェルスクリプトに関数を配置し、findから呼び出すことができます

# dosomething.sh
dosomething () {
  echo "doing something with $1"
}
dosomething $1

次に、findで次のように使用します。

find . -exec dosomething.sh {} \;
1
codaddict

関数を別のファイルに入れ、findを取得して実行します。

シェル関数は、定義されているシェルの内部にあります。 findはそれらを見ることができません。

1
Angus

参考までに、私はこのシナリオを次の方法で回避します。

for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
  _script_function_call $i;
done;

現在のスクリプトファイルで検索の出力を取得し、必要に応じて出力を繰り返します。私は受け入れられた答えに同意しますが、スクリプトファイルの外部に関数を公開したくありません。

1
dinesh saini

直接ではありませんFindは、シェルではなく、別のプロセスで実行されます。

関数と同じジョブを実行するシェルスクリプトを作成し、-execそれを見つけることができます。

0