ディレクトリ内のファイルのサブセットの名前を変更する

ディレクトリ内のファイルのサブセットの名前を変更する

私のディレクトリには何十万ものファイルがあります。ファイル名は次のとおりです。

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.sh1-0パディングが必要なファイルにのみ適用されるように、イテレータをどのように変更できますか?

touch2-?のコマンドを使用して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。安全のためです。

関連情報