xargs -Iとsedを組み合わせる

xargs -Iとsedを組み合わせる

find を使用して特定のファイルを検索し、xargs と cp および sed を使用してこれらのファイルを別のフォルダーに移動して名前を変更したいと考えています。これをループで実行する方法はわかっていますが、それは私が探しているものではありません。

私は試した:

find ${FOLDER} -iname "*${SOME_STRING}*" | xargs -I {} cp {} $(echo {} | sed 's/ABC/XYZ/g')

なぜこれが機能しないのでしょうか、そして解決策は何でしょうか?

答え1

これを試してみてください。 は必要ありませんxargs。 と だけfindですsedcopyファイルは変更されませんが、意思ファイルをコピーするためのシェル コマンドのリストを出力します。出力されるコマンドが気に入ったら、再度実行して最後の行の#の前のを削除しsh -x、シェルにコマンドを実行させます。

find "${FOLDER:-.}" -iname "*${SOME_STRING:-ABC}*" |
sed "
    s/^/'/                      # surround filename with single quotes
    s/$/'/
    h                           # save filename in the sed hold space
    s/ABC/XYZ/g                 # change filename
    H                           # append to hold space (separates with newline)
    g                           # get original and modified from hold
    s/\n/ /g                    # replace the newline with a space
    s/^/cp -i/                  # make it into a copy command
"  #| sh -x                     # optionally pipe to shell

なぜこのアプローチがxargsこのケースよりも優れているのでしょうか? この方法では、各ファイルに必要なコマンドに加えて、合計 3 つのプロセス ( findsed、 ) のみが開始されるためです。shcp

を使用する場合xargs、各ファイル名の処理には、単一の必須cpコマンドよりも多くのプロセスが必要になります。

sedを1回呼び出すだけで、全て各ファイル名ごとにcp新しいプロセスを呼び出すよりも、コマンドのほうが簡単です。sed

答え2

GNU Parallel を使用すると次のようになります。

find ${FOLDER} -iname "*${SOME_STRING}*" |
  parallel cp {} '{= s/ABC/XYZ/g =}'

{= =} 構造には、$_ を変更する Perl 式が含まれています。

利点の 1 つは、次のようなファイルがある場合でも、GNU Parallel が適切に動作することです。

My brother's 12" records worth >100$.txt

あるいは次のような恐ろしいこと:

touch Y-"$(perl -e 'print pack("c*",1..9,11..46,48..255)')"

関連情報