これに関するオンライン文書がたくさんあり、bash
マニュアルページも非常に素晴らしいです。それにもかかわらず、なぜこれがうまくいかないのかわかりません。どうやら何か抜けたようですが…
file010
、file020
...という名前の100個のファイルを含むディレクトリがありますfile1000
。私はそれらの名前をnew00..99
usingに変更したいと思いますmv
(mvg
実際には両方とも同じ出力を持ちます)。次のいずれかを実行すると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桁が長すぎます)。010
020
030
990
file
file1000
ループ内のファイル名を変更するには、ゼロから世紀を開始するカウンタを保持できます。その後、新しいファイル名はプレフィックスで構成され、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*