すべてのディレクトリとファイル名の文字列を別の文字列に再帰的に変更したいと思います。したがって、fooをbarに置き換えてこのファイルを使いたい場合:
foo_project/my_app/old_foo/start_foo.sh
欲しい
bar_project/my_app/old_bar/start_bar.sh
これはできましたが、とても醜いです。メモリから書き込む(コピーおよび貼り付けができませんので、誤字を許してください)私のコマンドは次のとおりです。
find $PROJECT_DIR -name "*foo*" | tac | xargs -n 1 -I % bash -c "eval mv % \$\( echo % \| sed \''s/\(.*\)foo/\1$PROJECT_NAME/'\' \)"
これは私にとって効果的ですが、ひどいです。私が欲しいものをもっときれいにする方法はありますか?
上記のコマンドのコンテキストを提供するために、古い rename コマンドがパスを異なるようにして、後で mv コマンドを中断するという問題がありました。そのため、最も深くネストされた名前変更を最初に実行したことを確認するために、xargsの前に(起動するための-evalcmd引数の代わりに)tacに切り替えました。その後、sedの名前を変更する必要がありました。最後名前を変更する前にフォルダ内のすべてのアイテムを移動できるようにするfooのインスタンス。
醜い部分は、evalが必要なので、xargsの内容をsedコマンドに渡す方法がわからないため、複数レベルのパラメータエスケープが必要であることです。それでも何かもっときれいになるでしょうか?
答え1
rename
CentOSまたはCentOSを持たない一部のシステム(時々呼び出されるprename
)を使用する場合繰り返し提案見やすいところです。 Debian 派生製品を使用している場合は、次の方法も役に立ちます。
find "$PROJECT_DIR" -depth -type d -execdir echo rename 's/foo/bar/' {} +
これによりディレクトリツリーが削除されます。深さ優先各ディレクトリのすべてのプロジェクト名を各インスタンスからに変更しますfoo
。bar
(実際にはどうなるかを見せる以外は何もしません。echo
満足すれば取り除いてください...)
答え2
このように、潜在的にトリッキーで危険な可能性があるタスクの場合は、目的のタスクを実行するスクリプトを生成するのが好きです。
$ find foo_project -print > /tmp/list
$ vi /tmp/list
:%s/.*/'&'/ # quote all filenames just to be safe
:%s/.*/mv & &/ # generate mv commands
:%s/' '/'\r'/ # break them for the next step
:v/^mv /s/foo/bar/g # modify the second arguments
:g/^mv /j # re-join the lines
今しばらく時間をかけて作成したスクリプトを確認し、必要に応じて機能することを確認します。
mv 'foo_project/my_app/old_foo/start_foo.sh' 'bar_project/my_app/old_bar/start_bar.sh'
...
あなたがこれが好きなら:
:wq
$ sh /tmp/list
これは私がいつも使用する一般的な技術です。スクリプトを編集する正確な方法は、実行する操作によって異なります。セクシーな冗談ではありませんが、安全です。
これが一回限りの作業ではなく定期的に実行したい場合、この手法は望むものではないかもしれません。ただし、ワンタイム操作(感じで実行する必要がある場合)の場合、これはうまく機能します。
今すぐ再利用可能なソリューションが必要な場合は、スクリプトを作成する必要があります。
#!/bin/sh
find foo_project -print | while read filename; do
newname=`echo $filename | sed -e 's/foo/bar/g'`
echo "renaming $filename => $newname"
mv "$filename" "$newname"
done