「bash」を使用して中括弧を拡張する

「bash」を使用して中括弧を拡張する

これに関するオンライン文書がたくさんあり、bashマニュアルページも非常に素晴らしいです。それにもかかわらず、なぜこれがうまくいかないのかわかりません。どうやら何か抜けたようですが…

file010file020...という名前の100個のファイルを含むディレクトリがありますfile1000。私はそれらの名前をnew00..99usingに変更したいと思いますmvmvg実際には両方とも同じ出力を持ちます)。次のいずれかを実行するとtarget 'new99' is not a directory(常に最後の項目)が得られます。

私は何を見逃していますか?

id@machine  ~/temp/test  ls
file010  file090   file160  file240  file320  file400  file480  file560  file640  file720  file800  file880  file960
file020  file100   file170  file250  file330  file410  file490  file570  file650  file730  file810  file890  file970
file030  file1000  file180  file260  file340  file420  file500  file580  file660  file740  file820  file900  file980
file040  file110   file190  file270  file350  file430  file510  file590  file670  file750  file830  file910  file990
file050  file120   file200  file280  file360  file440  file520  file600  file680  file760  file840  file920
file060  file130   file210  file290  file370  file450  file530  file610  file690  file770  file850  file930
file070  file140   file220  file300  file380  file460  file540  file620  file700  file780  file860  file940
file080  file150   file230  file310  file390  file470  file550  file630  file710  file790  file870  file950
 id@machine  ~/temp/test  mv {*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
 ✘ id@machine  ~/temp/test  mv {file{010..1000..10},new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
 ✘ id@machine  ~/temp/test  mv {file*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory

答え1

あなたは何を見逃していますか?mv仕組み。

正確に2つのファイルを提供する場合は、最初のファイル名を2番目のファイル名に変更してください。

ファイルが2つ以上の場合、最後の引数はディレクトリとして扱われ、前の引数はすべてディレクトリに移動するファイルです。

引用するマニュアルページ

ファイル名を変更するにはループが必要です。

i=0
for file in *; do
    mv -v "$file" "$(printf 'new%02d' $i)"
    ((i++))
done

アイデア:ファイルが100個を超えるとどうなりますか?ハードコーディングを避ける方法は%02d

files=(*)
num=$(( ${#files[@]} - 1 ))
size=${#num}
for idx in "${!files[@]}"; do
    mv -v "${files[idx]}" "$(printf 'new%0*d' $size $idx)"
done

答え2

rename 100ファイルを使用するには、個々のファイルの名前を変更するには100回mv呼び出す必要があります。mv実質的な解決策はありません。

file010数値順にファイルを繰り返すには、次のようにfile1000します。

for name in file{010..990..10} file1000
do
    # rest of code goes here
done

文字列などで最大10ステップまで{010..990..10}拡張できる中かっこ拡張です。これらの各文字列には文字列プレフィックスが付いています。数字がパターンに合わないため、末尾に追加します(1桁が長すぎます)。010020030990filefile1000

ループ内のファイル名を変更するには、ゼロから世紀を開始するカウンタを保持できます。その後、新しいファイル名はプレフィックスで構成され、fileその後にカウンタの現在の値に従ってゼロで埋められた2桁の整数が続きます。

上記のループに以下を追加します。

count=0
for name in file{010..990..10} file1000
do
    printf -v newname 'file%.2d' "$(( count++ ))"
    mv -- "$name" "$newname"
done

forまたは、次のように中括弧拡張の代わりに算術ループを使用できます。

for (( i = 1; i <= 100; ++i )); do
    printf -v name    'file%.3d' "$(( i * 10 ))"
    printf -v newname 'file%.2d' "$(( i - 1 ))"

    mv -- "$name" "$newname"
done

rename代わりにPerlユーティリティを使用してくださいmv

rename -n -v 's/file(\d+)/sprintf "file%.2d", ($1\/10 - 1)/e' file*

これは、現在のディレクトリで一致するすべてのファイル名にPerl s///(代替)式を適用します。file*この式は部分文字列の後の数字と一致し、fileそれを使用して新しいファイル名番号を計算します(10で除算して1を減算します)。

-n実行コマンドを「実際に」削除しました(-n「テスト実行」オプションです)。

/e代替文字列を評価せずに一度だけ言及するよりきれいなバリエーションfile

rename -n -v '/(file)(\d+)/; $_ = sprintf "%s%.2d", $1, ($2/10 - 1)' file*

関連情報