次のコマンドを使用して、パス内にAAA
を含む名前のファイルを検索しています。
find path_A -name "*AAA*"
上記のコマンドの出力を踏まえて、これらのファイルを別のパスに移動したいとします。たとえば、path_B
。それらのファイルを1つずつ移動する代わりに、findコマンドの直後にそれらのファイルを移動することで、コマンドを最適化できますか?
GNU mv の場合:
find path_A -name '*AAA*' -exec mv -t path_B {} +
これは、findの-exec
オプションを使用して、{}
を各検索結果に順番に置き換え、指定したコマンドを実行します。 man find
で説明されているように:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command until
an argument consisting of `;' is encountered.
この場合、+
の-exec
バージョンを使用しているので、実行するmv
オペレーションはできるだけ少なくします。
-exec command {} +
This variant of the -exec action runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invoca‐
tions of the command will be much less than the number of
matched files. The command line is built in much the same way
that xargs builds its command lines. Only one instance of `{}'
is allowed within the command. The command is executed in the
starting directory.
以下のようなこともできます。
find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B
どこ、
-0
空白や文字(改行を含む)があると、多くのコマンドが機能しません。このオプションは、空白のあるファイル名を処理します。-I
initial-arguments内のreplace-strの出現箇所を標準入力から読み取られた名前に置き換えます。また、引用符で囲まれていない空白は入力項目を終了しません。代わりに、区切り文字は改行文字です。テスト
sourcedir
とdestdir
の2つのディレクトリを作成しました。今、sourcedir
内にfile1.bak
、file2.bak
、file3 with spaces.bak
として一連のファイルを作成しました
今、私はコマンドを次のように実行しました:
find . -name "*.bak" -print0 | xargs -0 -I {} mv {} /destdir/
destdir
の内部でls
を実行すると、ファイルがsourcedir
からdestdir
に移動したことがわかります。
参照
http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/
この質問に出くわすOS Xユーザーのために、OS Xの構文は少し異なります。 path_A
のサブディレクトリを再帰的に検索したくない場合:
find path_A -maxdepth 1 -name "*AAA*" -exec mv {} path_B \;
path_A
ですべてのファイルを再帰的に検索する場合:
find path_A -name "*AAA*" -exec mv {} path_B \;
-exec
がこれを行うための最良の方法です。何らかの理由でこれがオプションではない場合は、ループで結果を読み取ることもできます。
find path_A -name "*AAA*" -print0 |
while IFS= read -r -d $'\0' file; do mv "$file" path_B; done
これは安全な方法です。スペース、改行、その他の奇妙な文字を含むファイル名を処理できます。より簡単な方法ですが、-ファイル名が単純な英数字のみで構成されていない限り失敗します、
mv $(find path_A -name "*AAA*") path_B
ただし、whileループを使用します。
find path_A -name '*AAA*' -exec sh -c 'mv "$@" path_B' find-sh {} +
参考文献:
別の方法
for f in `find path_A -name "*AAA*"`; do mv $f /destination/dir/; done