web-dev-qa-db-ja.com

変数を展開したbashスクリプトで-execを検索

以下のようなコマンドを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:私の問題は、_コマンドでshを実行する最初のオプションの前に-execがないことでした。 findコマンドを機能させる方法に興味がある人は、_を追加してください。すべてうまくいきます。

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

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

14
Matthew

特定の種類のファイルを特定のディレクトリにコピーしますか?これは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"
6
J. M. Becker

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

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

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

6
SiegeX

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-フラグにも依存しています。

もちろん、TechZillaはこれまでのところ、cpを呼び出すためにshは必要ありません。

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

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