単一の 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それはPerlの名前変更(どのバリエーションでも構いません)。

答え2

次のように出力されます:

mv ...

まさに私が実行したいコマンドです。しかし、実行できません。

出力を変数に割り当て、変数を呼び出して実行してみました。うまくいきませんでした。そのアイデアのバリエーションをいくつか試してみましたが、エラーが発生しました。

何かツールが足りない気がします。

あなたが探している簡単な方法コマンドに追加することです| bash。これにより、「コマンドを出力するコマンド」から「出力されたコマンドを実際に実行する」ことができます。

しかし、印刷するコマンドに二重引用符を含めたとしても、これは悪いアイデアスクリプトに含める。

空白文字についてはすでに処理済みかもしれませんが、ファイル名に二重引用符が直接含まれている場合はどうでしょうか? または改行文字? または変数名 (二重引用符内で展開されます) は?

のみファイル名に使用できない文字はスラッシュ ( /) とヌルバイトです。

スクリプトを作成する場合、対話型のコマンド ラインよりもはるかに高い堅牢性の基準を満たす必要があります。

コマンドラインでは、実行しようとしているコマンドが表示され、それが正しいことを確認してから実行できます。スクリプトでは、監視や確認はありません。スクリプトは、それがどんなに破壊的なものになるとしても、指示されたとおりに動作します。

だから正しいアプローチはfind、実際には私のその他の回答. これで処理されますどれでもファイル名が正しく、任意のコード実行の脆弱性は含まれていません。

答え3

もう 1 つの答えは、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]$ 

関連情報