web-dev-qa-db-ja.com

findコマンドの後にmvコマンドを統合する方法は?

次のコマンドを使用して、パス内にAAAを含む名前のファイルを検索しています。

find path_A -name "*AAA*"

上記のコマンドの出力を踏まえて、これらのファイルを別のパスに移動したいとします。たとえば、path_B。それらのファイルを1つずつ移動する代わりに、findコマンドの直後にそれらのファイルを移動することで、コマンドを最適化できますか?

67
huahsin68

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.
96
cuonglm

以下のようなこともできます。

find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B

どこ、

  1. -0空白や文字(改行を含む)があると、多くのコマンドが機能しません。このオプションは、空白のあるファイル名を処理します。
  2. -I initial-arguments内のreplace-strの出現箇所を標準入力から読み取られた名前に置き換えます。また、引用符で囲まれていない空白は入力項目を終了しません。代わりに、区切り文字は改行文字です。

テスト

sourcedirdestdirの2つのディレクトリを作成しました。今、sourcedir内にfile1.bakfile2.bakfile3 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/

25
Ramesh

この質問に出くわす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 \;
23
mannykary

-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ループを使用します。

6
terdon

find のPOSIX機能のみを使用(および mv ):

find path_A -name '*AAA*' -exec sh -c 'mv "$@" path_B' find-sh {} +

参考文献:

5
Wildcard

別の方法

for f in `find path_A -name "*AAA*"`; do mv $f /destination/dir/; done
2
user13107