findを使用して複数のファイルの名前を変更する方法

findを使用して複数のファイルの名前を変更する方法

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

関連情報