変数展開のあるbashスクリプトで-execを見つける


14

bashスクリプトで次のようなコマンドを実行しようとしています。のすべてのサブフォルダーを検索し$sourcedir、特定の種類のすべてのファイルをのルートレベルにコピーする必要があります$targetdir

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;

ことを除いて、これは、かなり近いように思える{}ように渡されていない$2-exec sh -c ...

これをできる限り「正しい方法」に近づけ、ファイル名の特殊文字(具体的には一重引用符文字)の許容範囲内で行いたいと思います。

編集:私は人々がxargs引数チェーンを使用することを提案しているのを見ます。私は、これは限られた数の議論に対してのみ大丈夫であるという印象を受けていました。たとえば、多数のギャラリーディレクトリから巨大なスライドショーディレクトリにコピーしようとしている数千の.jpgファイルがある場合、引数をチェーン化したソリューションは引き続き機能しますか?

編集2:私の問題は_-execコマンドでshする最初のオプションの前に行方不明でした。findコマンドを機能させる方法に興味がある人は_、すべて追加してください。

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

ただし、同じタスクを実行しますが、より効率的でエレガントなので、以下の回答を受け入れました。


4
それがまさに、xargs制限のある通常のコマンドの膨大な量の引数を自動的に処理するために作成された理由です。また考慮すべき点として、最大引数の制限のほとんどは、標準のGNU utilsで大幅に改善されています。また、何千ものファイルに関連するプロセスフォークをすべて回避することで、パフォーマンス上のメリットが得られます。
JMベッカー

「;」の代わりにgnu-findと+を使用すると、複数の引数を同時にfindで処理できます。そして、-print0で渡す複雑な引数を保存します。
ユーザー不明

@userunknown:あなたの答えの下でこれに答えています。
JMベッカー

@user unknownさて、私はこのコードが大好きです。少なくともPOSIXに完全に準拠しており、マシン上でGNUを使用しなくても動作します。特に職場のサーバーでは、これ必要な場合あります。
構文エラー

回答:


6

特定のタイプのファイルを特定のディレクトリにコピーしますか?これはで行うのが一番でxargs、それさえ必要ありませんsh。これはより適切な方法であり、より効率的に実行する必要があります。

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

特殊なファイル名を処理する必要がある場合はNULL、セパレータとして使用します

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

1
第二の場合には、追加することを忘れないでください-print0findして-0xargs
SiegeX

@ SiegeXは、私があなたのコメントに気付く前に、すでにそうしていた。
JMベッカー

また、NULLを使用する場合は必要'{}'ありません。使用しない場合は重要です。POSIXコンプライアンス以外の、どちらか一方の間の本当の利点はパフォーマンスです。
JMベッカー

6

{}引数としてシェルに渡してから、各引数をループする必要があります。

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

:これが機能する方法は、シェルへの最初の引数がシェルの名前であるということです。名前をとして渡し、シェルスクリプト内の$targetdir特別なパラメーターを使用して$0そのtargetdirにアクセスすることでこれを利用できます。


1
"$targetdir"単一引用符内では展開されません。
enzotib

5

xargsの教会を信じない場合:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

説明:

cp -t a b c d 

b、c、dをターゲットディレクトリaにコピーします。

-exec cmd {} +

大量のファイルに対してコマンドを一度に呼び出しますが、次から次へではありません(の";"代わりに使用する場合は標準です+)。これが、targetdirを先頭に引き、明示的にターゲットとしてマークする必要がある理由です。

これはgnu-findで機能し、findの他の実装では機能しない可能性があります。もちろん、-t -flagにも依存しています。

TechZillaは、shcpを呼び出すために必要ではないので、もちろんこれまでのところ右端にあります。

を使用しない場合xargs、ほとんどの場合、と組み合わせて不必要になりfind-print0and -0フラグを学習する必要がなくなります。


1
当然のことながら、誰が好むかもしれないどの方法は非常に主観的です。とはいえ、まだ使用する理由がありますxargs。最大の例、ファイルが見つからない場合はどうなりますか?私はfor常に一般的なループの代わりにxargsを使用してfindいますが、スコープはずっと小さくなっています。さらに、GNUを使用findしている+場合にのみサポートしますfind。これはPOSIXでは定義されていません。したがって、find単独で自由に選択する必要がありますが、xargsが行うすべてのことを行うわけではありません。GNUを検討するとき、マルチコアをxargs実行するものも取得-Pします。xargs関係なく、学ぶ価値があります。
JMベッカー

主観的に言えば、私の意見は明らかに異なります。一方、客観的には、あなたの答えも正しいです。これは、利用可能な数少ない最良のソリューションの1つです。
JMベッカー

@TechZilla:findが並行呼び出しのサポートを開始したら、このサイトを再訪することを忘れないでください。:)コピー/移動のほとんどの場合、ディスク速度が制限要因になりますが、SSDは状況を変える可能性があります。GNU以外のソリューションを提供することは素晴らしいことです。それ以外の場合、find-solutionは客観的に短く、単純で、2つのプロセスのみを使用します。
ユーザー不明

0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;

3
ソリューションの説明を追加することを検討してください。
HalosGhost 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.