コマンドfind
コマンドを使用して、複数のファイル(file1 ... filenをfile1_renamed ... filen_renamed)に名前変更したい:
find . -type f -name 'file*' -exec mv filename='{}' $(basename $filename)_renamed ';'
しかし、このエラーが発生します:
mv: cannot stat ‘filename=./file1’: No such file or directory
ファイル名がシェル変数として解釈されないため、これは機能しません。
以下はあなたのアプローチの直接的な修正です:
find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;
ただし、一致するファイルが多数ある場合、一致ごとに新しいシェル(mv
を実行する)を開始するため、これは非常に負荷がかかります。また、ファイル名に変な文字が含まれていると、爆発します。より効率的で安全なアプローチは次のとおりです。
find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed
また、奇妙な名前のファイルを操作できるという利点もあります。 find
がサポートしている場合、これは
find . -type f -name 'file*' -exec mv {} {}_renamed \;
xargs
バージョンは、{}
を使用しない場合に便利です。
find .... -print0 | xargs --null rm
ここでrm
は1回(または多くのファイルで数回)呼び出されますが、すべてのファイルに対して呼び出されるわけではありません。
basename
を削除しました。おそらく間違っているためです:foo/bar/file8
ではなくfile8_renamed
をfoo/bar/file8_renamed
に移動します。
編集(コメントで提案されているとおり):
find
なしの短縮されたxargs
を追加最初の答え を試して少しいじった後、-execdir
を使用すると、少し短くて簡単な方法で実行できることがわかりました。
find . -type f -name 'file*' -execdir mv {} {}_renamed ';'
それはまたあなたが必要とするものを正確に行うべきであるように見えます。
別のアプローチは、find
出力に対してwhile read
ループを使用することです。これにより、find
のsh -c
オプションを使用して個別の-exec
プロセスを生成することによる追加のコスト/潜在的なセキュリティ問題を心配する必要なく、操作可能な変数として各ファイル名にアクセスできます。
find . -type f -name 'file*' |
while IFS= read file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
また、使用しているシェルが-d
オプションをサポートしてread
区切り文字を指定している場合、次のようにして、奇妙な名前のファイル(たとえば改行付き)をサポートできます。
find . -type f -name 'file*' -print0 |
while IFS= read -d '' file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
最初の答え を展開したいと思います。./
パス接頭辞がファイル名引数に存在するため、これはファイル名に追加することはできません。
Thomas Erkerの回答を変更して、これはより一般的なアプローチだと思います
find . -name PATTERN -printf "%f\0" | xargs --null -I{} mv {} "prefix {} suffix"
xargsオプション:
--null
stdin
を介して渡される各引数がnull文字(\0
)で終わることを示します。このように、ファイル名にスペースを含めることができます。そうしないと、各Wordがmv
コマンドの異なるパラメーターとして脅かされます。
-I replace-str
replace-str
が出現するたびに、stdin
から読み取られた引数に置き換えられます。したがって、必要に応じて他の文字列に変更することができます。
for
、find
、mv
でも同様のことができました。
for i in $(find . -name 'config.yml'); do mv $i $i.bak; done
これにより、すべてのconfig.yml
ファイルが見つかり、それらの名前をconfig.yml.bak
に変更します