私のディレクトリには何十万ものファイルがあります。ファイル名は次のとおりです。
left-00001.tiff
left-00002.tiff
...
left-99999.tiff
left-100000.tiff
...
left-245000.tiff
ファイル名を次のように変更したいと思います。
left-000001.tiff
...
left-099999.tiff
...
left-245000.tiff
この問題を解決するエレガントな方法を見つけましたここ。
ソリューションはというbashスクリプトを実装しますzeropad.sh
。 Bashエンコーディングは次のとおりです。
#!/bin/bash
num=`expr match "$1" '[^0-9]*\([0-9]\+\).*'`
paddednum=`printf "%06d" $num`
echo ${1/$num/$paddednum}
次のように繰り返し適用できますfor loop
。
for i in *.tiff;do mv $i `./zeropad.sh $i`; done
ただし、このソリューションはすでに正しく入力されているすべてのファイルの名前を変更するために不要な作業をたくさん実行するため、時間がかかります。i.e. as %06d type numbers
。私の目的では、このソリューションは非常に遅いです。
2つの質問があります。
zeropad.sh
1-0パディングが必要なファイルにのみ適用されるように、イテレータをどのように変更できますか?
touch
2-?のコマンドを使用してfor loop
テストデータを生成するには?スクリプトを生データに適用する前に、スクリプトが機能していることを確認することが重要です。
答え1
これが私が通常行う方法です(シェルで手動で)。
rename left- left-0 left-?.png # for 0-9
rename left- left-0 left-??.png # for 00-99
rename left- left-0 left-???.png # for 000-999
# result left-0000.png - left-9999.png
これは対話型シェルセッションで簡単に実行できます。最後のコマンドを繰り返して追加の?
コマンドを追加するだけです。
ただし、ファイル数が多いとパラメータリストが長くなりすぎます。明らかに、これは同じファイルの名前を複数回変更するので、最も効率的なオプションではありません(left-1.png -> left-01.png -> left-001.png -> ...)。
Aboutには2つのスタイルがありますrename
。 1つはPerl正規表現を使用し、もう1つは使用しません。ディストリビューションによって、rename.ul
またはperl-rename
、または別の名前で終わります。デフォルトではrename
何が起こるのかわからないので、このコマンドを使用するスクリプトを移植できないようにします。
私はutil-linux renameを使用しており、あなたの質問は実際にはマニュアルページの例の1つです。
EXAMPLES Given the files foo1, ..., foo9, foo10, ..., foo278, the commands rename foo foo00 foo? rename foo foo0 foo?? will turn them into foo001, ..., foo009, foo010, ..., foo278.
000
どの方法がより効率的ですが(各ファイルの名前を一度だけ変更する)、vsの正しい分布を見つける必要があります。???
それ以外の場合、誤った結果が発生します。
私にとっては、非効率的なアプローチがインタラクティブシェルでかなり小さなファイルセットで作業するとき、より実用的なアプローチです。
スクリプトを直接書くよりも利点は、各ファイルのプロセスを作成する必要がrename
ないこと、またはファイル名を見つけるために下付き文字のみを使用する必要がないことです。mv
オーバーヘッド、プロセス生成、または繰り返しの名前変更が何であるかは不明で、ベンチマークにはあまりにも怠惰です。
実際、あなたがリンクした回答には、すでにperl-renameを使用した「ベスト」ソリューションが含まれています。
rename 's/\d+/sprintf("%04d",$&)/e' *.png
まあ、誰かが正規表現について議論するかもしれませんが、ポイントはmv
不必要なプロセスなしに一度にすべてを行うことが可能であるということです。それでも改善する必要がある場合は、シェルワイルドカード(ある種の遅い)を使用するのではなく、ディレクトリの内容を直接読み、必要に応じて名前を変更するツールを作成してください。
たぶんこれは実際にあなたがつながった答えかもしれないので、あなたは反対の表を受け取ったかもしれません。 ;)
答え2
高価なのは、あまりにも多くのプロセスをフォークし、各ファイルに対してあまりにも多くのコマンドを実行することです。
そしてzsh
:
zmodload zsh/files # make mv builtin to speed things up
autoload zmv
zmv -n '(*-)(<->)(.tiff)' '$1${(l:6::0:)2}$3'
-n
(満足すれば削除)
これらはすべて組み込み機能なので、プロセスは分岐せず、ファイルは実行されません。
またはperl
次のようにrename
:
rename -n 's/\d+(?=\.tiff\z)/sprintf "%06d", $&/e' ./*[0-9].tiff
答え3
ループはおそらくほとんどの時間をzeropad.sh
スクリプトを呼び出すのに費やすでしょう。
代わりに、1つのスクリプトですべてを実行してください。
#!/bin/bash
for filename in left-*.tiff; do
if [[ "$filename" =~ ^left-0*([1-9]?[0-9]+)\.tiff$ ]]; then
num=${BASH_REMATCH[1]}
newname="left-$( printf '%06d' "$num" ).tiff"
if [ "$filename" != "$newname" ] && [ ! -e "$newname" ]; then
echo mv "$filename" "$newname"
fi
fi
done
echo
スクリプトが正しい操作を実行していることを確認したら、それを削除してください。
答え4
私はPerlのジョークが好きです:
ls left-*.tiff | perl -ne 'if(m/(\S+)-(\d+).tiff/){chomp;printf "mv $_ left-%06d.tiff\n", $2}' | bash
PS、入力を配管する前に出力を再確認してくださいbash
。安全のためです。