
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
ファイル名がシェル変数として解釈されないため、機能しません。
答え1
あなたのアプローチに対する簡単な修正は次のとおりです。
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
一度(または多くのファイルでは複数回)呼び出されますが、すべてのファイルに対して呼び出されるわけではありません。
basename
ご質問が間違っている可能性があるため削除しました。foo/bar/file8
代わりfile8_renamed
に移動しますfoo/bar/file8_renamed
。
編集する(コメントで提案したように):
find
短縮追加なしxargs
- 安全ステッカーが追加されました。
答え2
試した後最初の答え少し遊んだ後、私は次のコマンドを使って少し短くて簡単にすることができました-execdir
。
find . -type f -name 'file*' -execdir mv {} {}_renamed ';'
それはあなたが必要とするものを正確に行う必要があるようです。
答え3
while read
別の方法はループ出力を使用することですfind
。これにより、オプションをsh -c
使用して別々のプロセスを作成するための追加コスト/潜在的なセキュリティ問題を心配することなく、各ファイル名を操作できる変数としてアクセスできます。find
-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
答え4
、およびを使用してfor
同様のfind
操作を実行できましたmv
。
for i in $(find . -name 'config.yml'); do mv $i $i.bak; done
config.yml
その後、すべてのファイルを見つけて名前を次に変更します。config.yml.bak