複数のコマンドで-execを検索


430

find -execを複数のコマンドで使用しようとしていますが、成功しません。次のようなコマンドが可能かどうか誰かが知っていますか?

find *.txt -exec echo "$(tail -1 '{}'),$(ls '{}')" \;

基本的に、私は現在のディレクトリの各txtファイルの最後の行を印刷し、行の最後に印刷し、コンマの後にファイル名を続けようとしています。



1
コマンドの可能性を確認する限り、システムで試してみませんでしたか?
スリラム

1
findマニュアルページから:There are unavoidable security problems surrounding use of the -exec option; you should use the -execdir option instead.unixhelp.ed.ac.uk/CGI/man-cgi?find
JVE999


@ JVE999リンクが壊れており、ss64.com / bash / find.htmlで代替
キースM

回答:


659

find-execコマンドに複数の部分を受け入れます。例えば:

find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;

この場合、@ Calebで言及されているように、2番目のコマンドは最初のコマンドが正常に戻った場合にのみ実行されることに注意してください。成功または失敗に関係なく両方のコマンドを実行する場合は、次の構文を使用できます。

find . -name "*.txt" \( -exec echo {} \; -o -exec true \; \) -exec grep banana {} \;

2回グレップする方法?これは失敗しています:./* -exec grep -v 'COLD、' {} \;を見つけます。-exec egrep -i "my_string" {} \;
rajeev 2013年

51
@rajeev 2番目のexecは、最初のexecの戻りコードが成功を返した場合にのみ実行され、それ以外の場合はスキップされます。これはおそらく、この回答で注意する必要があります。
Caleb

1
これが答えになります
pylover 2017

1
-n他のいくつかの回答でを使用して、エコーによって生成された改行を抑制することに注意してください。これは、2番目のコマンドが1行の出力しか生成せず、読みやすくしたい場合に便利です。
William Turrell

素晴らしいソリューション。魅力のように機能します。
Philippe Delteil

98
find . -type d -exec sh -c "echo -n {}; echo -n ' x '; echo {}" \;

3
Bourneの代わりにBashを実行したい場合は、の... -exec bash -c ...代わりに使用することもできます... -exec sh -c ...
Kenny Evitt

9
{}シェルコードに埋め込まないでください。unix.stackexchange.com/questions/156008/…を
Kusalananda

3
+1 @Kusalanandaファイル名の注入は壊れやすく、安全ではありません。パラメータを使用します。SC2156を
pambda

52

次のいずれか:

find *.txt -exec awk 'END {print $0 "," FILENAME}' {} \;

find *.txt -exec sh -c 'echo "$(tail -n 1 "$1"),$1"' _ {} \;

find *.txt -exec sh -c 'echo "$(sed -n "\$p" "$1"),$1"' _ {} \;

12
{}の前のアンダースコアは何ですか?
2013

2
@qed:の場所を保持する使い捨ての値です$0。「_」の代わりに「foobar」を使用してこれを試してください。- find /usr/bin -name find -exec sh -c 'echo "[$0] [$1]"' foobar {} \;出力:「[foobar] [/ usr / bin / find]」。
追って通知があるまで一時停止。

1
@XuWang:はい、そうです。ご存知のとおり、$0通常はプログラム名(ARGV[0])です。
追って通知があるまで一時停止。

3
この方法では、渡されるスクリプトがsh -c二重引用符ではなく単一引用符で囲まれていることが重要です。それ以外の場合$1は、スコープが間違っています。
Nick

1
@Nick引用符はそれとは関係ありません。'$1'変数("\$1")をエスケープする限り、二重引用符で記述できます。他の文字もエスケープできます("\"")。
Camilo Martin

22

別の方法は次のとおりです:

multiple_cmd() { 
    tail -n1 $1; 
    ls $1 
}; 
export -f multiple_cmd; 
find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;

一列に

multiple_cmd() { tail -1 $1; ls $1 }; export -f multiple_cmd; find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;
  • multiple_cmd()」-関数です
  • " export -f multiple_cmd"-他のサブシェルがそれを見ることができるようにそれをエクスポートします
  • " find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;"-あなたの例で関数を実行することがわかります

このように、multiple_cmdは必要に応じて長く複雑にすることができます。

お役に立てれば。


完璧、ちょうど私が必要としたもの!
エントロピー

OSXでは動作しません
Thomas

@Thomasそれはそうですが、osxでテストされたこの1つのライナーを試してください。そこにいくつかのファイル/ディレクトリを含む「aaa」というディレクトリを作成し、それにCDdを作成しました。その後、 ~/aaa$ acmd() { echo x \"$1\" x; }; export -f acmd; find . -exec bash -c 'acmd {}' \;
barlop

@barlop、私はそれを試してみます。ありがとう!
トーマス

14

もっと簡単な方法があります:

find ... | while read -r file; do
    echo "look at my $file, my $file is amazing";
done

または:

while read -r file; do
    echo "look at my $file, my $file is amazing";
done <<< "$(find ...)"

1
ファイル名には改行を含めることができます。これが、findに-print0引数があり、xargsに-0引数がある理由です
abasterfield

@abasterfield私はいつも、野生のそれらを見つけないように願っていますlol
Camilo Martin

1
私がやりたかったことは、「find ... -exec zcat {} | wc -l \;」でした。うまくいきませんでした。ただし、見つける... | -rファイルの読み取り中。「$ file:zcat $file | wc -l」をエコーします; 完了しましたので、ありがとうございます!
グレッグドハティ2017

上記のコメントでは、「zcat $ file | wc -l」の周りに「バックティック」があります。私は目に見える正しいコードと実際の答えとして、それを追加しましたので、残念ながらSO、書式設定にそれらを回す
グレッグ・ドハティ

1
@GregDougherty `バックスラッシュをエスケープして、次のようにバックスラッシュを使用することができます\​`(それでも、$()代わりに使用するのはそれが理由です)。
Camilo Martin

8

findでこれを実行できるかどうかはわかりませんが、別の解決策として、シェルスクリプトを作成して、findでこれを実行する方法があります。

lastline.sh:

echo $(tail -1 $1),$1

スクリプトを実行可能にします

chmod +x lastline.sh

使用find

find . -name "*.txt" -exec ./lastline.sh {} \;

7
バックティックは廃止されました。読みやすく、フォントに依存せず、ネストが簡単な$(...)の使用をお勧めします。ありがとうございました。
ユーザー不明

4

デニスの最初の答えは、問題を解決するための答えです。しかし、実際には、タイトルが示唆するように、1つのexecのみにいくつかのコマンドがある検索はありません。1つのexecにいくつかのコマンドで応答するには、解決する他の何かを探す必要があります。次に例を示します。

複数の{}参照を使用する1つのexecコマンドを使用して、過去7日間に変更された.logファイルの最後の10000行を保持する

1)コマンドがどのファイルで何をするかを確認します。

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "echo tail -10000 {} \> fictmp; echo cat fictmp \> {} " \;

2)実行する:(これ以上「\>」ではなく「>」のみが必要であることに注意してください)

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "tail -10000 {} > fictmp; cat fictmp > {} ; rm fictmp" \;


しかし、ファイル名の1つにスペースがある場合、これは壊れると思います。
Camilo Martin

4

Camilo Martinのおかげで、関連する質問に答えることができました。

私がやりたかったことは

find ... -exec zcat {} | wc -l \;

うまくいきませんでした。しかしながら、

find ... | while read -r file; do echo "$file: `zcat $file | wc -l`"; done

動作しますので、ありがとうございます!


2

@Tinkerの答えを拡張して、

私の場合、command | command | command内部-execにファイル名と特定のテキストを含むファイルで見つかったテキストの両方を印刷する必要がありました。

私はそれを行うことができました:

find . -name config -type f \( -exec  grep "bitbucket" {} \; -a -exec echo {} \;  \) 

結果は次のとおりです。

    url = git@bitbucket.org:a/a.git
./a/.git/config
    url = git@bitbucket.org:b/b.git
./b/.git/config
    url = git@bitbucket.org:c/c.git
./c/.git/config

1
また、渡すことで、ファイル名と一行上grep'dコンテンツを印刷することができます/dev/nullに2番目の引数としてgrep1つのを指定して、コマンド-execパラメータ:find . -name config -type f -exec grep "bitbucket" {} /dev/null \;
ビル・Feth

1

xargsを使用する必要があります:)

find *.txt -type f -exec tail -1 {} \; | xargs -ICONSTANT echo $(pwd),CONSTANT

別のもの(OSXで作業中)

find *.txt -type f -exec echo ,$(PWD) {} + -exec tail -1 {} + | tr ' ' '/'

3
これは、find一致するファイルの数がコマンドラインに対して大きすぎる場合の主な使用例を見落とします。-execこの制限を回避する方法です。公益事業へのパイプアウトは、その利益を逃します。
Chris Johnson

xargs -n呼び出しごとの一致数を選択するために存在します。すべての試合でxargs -n 1 foocmd実行さfoocmd {}れます。
AndrewF

0

find+xargs答え。

以下の例では、すべての.htmlファイルを検索し、.BAK拡張子が付加されたコピーを作成します(例:1.html > 1.html.BAK)が。

複数のプレースホルダーを持つ単一のコマンド

find . -iname "*.html" -print0 | xargs -0 -I {} cp -- "{}" "{}.BAK"

複数のプレースホルダーを持つ複数のコマンド

find . -iname "*.html" -print0 | xargs -0 -I {} echo "cp -- {} {}.BAK ; echo {} >> /tmp/log.txt" | sh

# if you need to do anything bash-specific then pipe to bash instead of sh

このコマンドは意志のようなハイフンで始まるまたはスペースを含むファイルでも作業-my file.htmlパラメータのおかげで引用して--cpにその信号cpパラメータの終わりと実際のファイル名の先頭。

-print0 結果をnullバイトのターミネーターでパイプします。


ためxargsの-I {}パラメータが定義され{}、プレースホルダとして。好きなプレースホルダーを使用できます。-0入力項目がnullで区切られていることを示します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.