私はこれを単純なディレクトリ構造でテストしてきました。
「Season」という名前のディレクトリおよび/またはサブディレクトリを「Sn」に変更しようとしています。スクリプトが私が望むものを変更するポイントに達しました...下のリストに示すように、トップレベルのディレクトリは除外されます - 「シーズン1」「シーズン2」「シーズン3」。
ディレクトリ構造:
.
├── AnotherShow
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ └── Sn4
├── Movie1
│ ├── Sn1
│ └── Sn2
├── Movie2
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ └── Sn4
├── Movie3
│ ├── Sn1
│ └── Sn3
├── Movie4
│ ├── Sn2
│ └── Sn3
├── Season 1
├── Season 2
├── Season 3
├── Show
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ ├── Sn4
│ └── Sn5
└── TV
├── Sn1
├── Sn2
├── Sn3
└── Sn4
私のスクリプトは次のとおりです
array="$(find . -maxdepth 2 -type d -iname 'Season*' -print)"; # A more refined way to search for Seasons in a directory.
for dir in "${array[@]}"; do # Put this list into an array. Surround the array with quotes to keep all space s (if any) together.
new="$(echo "$dir" | sed -e 's/Season 0/Sn/' -e 's/Season /Sn/')"; # Only change Season 0 to SN. Leave othe rs alone.
sudo mv -v "$dir" "$new" && echo Changed "$dir" to "$new";
done
答え1
問題は配列を作成するのではなく、文字列を作成することです。配列の最初の要素を印刷すると、簡単にテストできます。
$ array="$(find . -maxdepth 2 -type d -iname 'Season*' -print)";
$ echo $array
./Season 3 ./Season 1 ./Season 2
大丈夫に見えますか?ただし、これが配列の場合は、各要素を個別に印刷できます。残念ながら、上記は配列ではなく単純な文字列1です。
$ echo ${array[0]}
./Season 3 ./Season 1 ./Season 2
$ echo ${array[1]}
配列は実際には単一の文字列で構成されるため、${array[1]}
「配列」の2番目の要素()は空です。いずれにせよ、このために配列を使用する必要はなく、読み込みの出力を使用するだけですfind
(あなたも同じです-print
。基本的にそれを行います)。スクリプトの作業バージョンは次のとおりです。
#!/usr/bin/env bash
find . -maxdepth 2 -type d -iname 'Season*' | sort -r |
while IFS= read -r dir
do
mv "$dir" ${dir/Season /Sn} && echo Changed "$dir" to "$dir/Season /Sn}";
done
ここではいくつかのトリックが使用されます。まずwhile
結果を繰り返しますfind
。これは使用したループと同じ基本原理ですが、標準入力からの読み出しとfor
組み合わせられます。read
空白による分割を避ける必要がありますIFS=
(空白がない場合、ディレクトリはSeason 1
およびで分割されます)。Season
1
of readはバックスラッシュエスケープ文字(および文字通り処理される文字)を -r
許可しないように指示し、最も奇妙な名前を処理できるようにします。\t
\n
これはsort -r
、一致する他のディレクトリのパターンと一致するディレクトリがある場合に、サブディレクトリが親ディレクトリの前にリストされるようにするために必要です。たとえば、
./Season 12/Season 13
./Season 12
これにより実行が保証されます。mv "Season 12" "Sn12"
後ろにランニングmv "Season 12"/"Season 13" "Season 12"/"Sn13"
。そうしないと、2番目のコマンドはSeason 12
もう存在しないため失敗します。
最後にを削除しましたsudo
。スクリプトをとして実行する必要がありますsudo script.sh
。sudo
スクリプトからランダムに呼び出すことは決して良い考えではありません。
1詳細はわかりませんが、bashは文字列変数を1つの要素の配列として扱います。
答え2
まだ問題が何であるかわかりませんが、あなたのスクリプトについていくつかのコメントがあります。
ループ内で(単一データを含む)バイナリファイルを呼び出さないでください。これはパフォーマンスに影響を与えます。
スクリプト全体を呼び出すにはsudoを使用する必要がありますが、スクリプト内では呼び出すことはできません。
sed
ファイル名を変更する必要はありません。bash
自分で行うことができます:
if [[ $dir =~ "Season 0" ]]; then
new="${dir/Season 0/Sn}"
else
new="${dir/Season /Sn}"
fi
またはif
:
new="${dir/Season /Sn}"
new="${new/Sn0/Sn}"
配列は必要ありません。
find ... | while read dirpath; do
これの「利点」は、ディレクトリ名の空白が配列定義を壊さないことです。あなたがなぜ働くのか分からないarray="$(find ... -print)"
。 (シェルはスペースと改行文字の間で単語分割を行わないため)そうしないでください。
答え3
上記の内容を簡単に変形したものです。
for dir in ./*/Season\ */
do
mv "$dir" "${dir/eason /n}" && echo "$dir changed to ${dir/eason /n}"
done
サブディレクトリで使用季節。 (ディレクトリだけでなく)ファイルの名前を変更するには、パターンの/
最後から削除すると次のようになります。./*/Season\ *
必要に応じて、sudo
スクリプトの代わりに1行のコマンドを使用してこれを実行することをお勧めします。
for dir in ./*/Season\ */ ; do sudo mv -v "$dir" "${dir/eason /n}" ; done