単一のbashコマンドを使用して一括してフォルダ名を変更する

単一のbashコマンドを使用して一括してフォルダ名を変更する

次のフォルダ設定があります。

/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3

SLUG_2は年であり、「1994」や「2003a」などの文字が後に続くことがあります。

このファイルの名前を次に変更したいと思います。

/path/to/directory/SLUG_1/SLUG_2 - SLUG_3

私はこのコマンドに非常に近いです。

find $root -mindepth 2 -maxdeth 2 -type d | sed "s#\(\(/path/to/directory/[^/]*/\).* - \([0-9]\{4\}[a-bA-B]\? - .*\)\)#mv "\1" "\2\3"#

これは以下を印刷します:

mv "/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3" "/path/to/directory/SLUG_1/SLUG_2 - SLUG_3"

これが私が実行したいコマンドです。しかし、実行することはできません。

出力を変数に割り当て、その変数を呼び出して実行してみました。それは動作しません。このアイデアをいくつか変えてみましたが、エラーが発生しました。

ここにいくつかのツールがありません。いくつかの繰り返しツールを使用すると、これを簡単に作成できます。どんな提案がありますか?

答え1

すべてのサブディレクトリが/path/to/directory次の命名規則に従うと仮定します。

cd /path/to/directory
prename -n 's~/\d{4}[a-z]? - ~/~i' */*

prename~であるパールの名前を変更する(どんなバリエーションでも可能です)。

答え2

これは以下を印刷します:

mv ...

これが私が実行したいコマンドです。しかし、実行することはできません。

出力を変数に割り当て、その変数を呼び出して実行してみました。それは動作しません。このアイデアをいくつか変えてみましたが、エラーが発生しました。

ここにいくつかのツールがありません。

あなたが探している簡単な方法| bashコマンドに追加されます。これが「コマンドを印刷するコマンド」から「実際に印刷を実行するコマンド」に移動する方法です。

しかし、印刷する命令に二重引用符を含めてもこれは悪い考えスクリプトに含まれます。

空白の問題を解決したかもしれませんが、ファイル名に二重引用符文字が直接含まれている場合はどうなりますか?それとも改行文字ですか?それとも変数名(二重引用符で拡張)ですか?

これただファイル名に無効な文字は、スラッシュ(/)とNULLバイトです。

スクリプトを作成するときは、対話型コマンドラインを使用する場合よりも高いレベルの堅牢性を維持する必要があります。

コマンドラインから実行したいコマンドが表示され、正しいことを確認して実行できます。台本には監督もなく、確認もありません。スクリプトは、いくら破壊的であっても、ユーザーが指示したとおりに実行します。

だから正しいこの方法は実際に使用しますfind。私の内容をご覧ください。その他の回答。これが処理するでしょうどのファイル名が正確で、任意のコード実行の脆弱性が含まれていません。

答え3

もう一つの答えは、GNUを使用してfind名前変更を処理することです。この方法は、ファイル名に含まれる文字に関係なく安定しています。

あなたのユースケースを正しく理解したら、親ディレクトリのフルネームで始まるディレクトリの名前を変更したいと思います。つまり、ディレクトリ名が次のような場合:

/some/path/abcdefghi/abcdefghi - something - else/

次のように名前を変更したいと思います。

/some/path/abcdefghi/something - else/

この質問でGNUをラベル付けしたので、findコマンドのGNU拡張を使用して次のように処理できます。

find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;

テスト結果:

[vagrant@localhost test]$ mkdir -p SLUG_1/SLUG_{1\ -\ SLUG_{2..4}\ -\ SLUG_5,7\ -\ something}
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_1 - SLUG_2 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_4 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_3 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_3 - SLUG_5
./SLUG_1/SLUG_4 - SLUG_5
./SLUG_1/SLUG_2 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ 

関連情報