番号の変更と名前の変更

番号の変更と名前の変更

次の形式で多数のファイル名を変更する必要がある状況が発生しました。

file.csv
file_1.csv
file_2.csv
file_3.csv
file_4.csv
file_5.csv
file_6.csv
file_7.csv
file_8.csv

より良いソートのためには、次のものが必要です。

file_1.csv
file_2.csv
file_3.csv
file_4.csv
file_5.csv
file_6.csv
file_7.csv
file_8.csv
file_9.csv

つまり、最初のファイルの名前を手動で変更することができますが、残りの " _#"ファイルについては+1

rename -n -v 's/_(.*)./.(\1+1)./' 

しかし、得た

file_(1+1).csv
file_(2+1).csv

など。

_#""ファイルを一括して保持する簡単な方法はありますか?

PS、まだ良いです

file_01.csv
. . .
file_09.csv
file_10.csv
. . .

可能であれば。

修正する:

答えてくれてありがとう。 0で埋められた名前に名前を変更したため、ファイル名が競合しないため、コマンドは次のように単純化されました。

touch file.csv file_{1..9}.csv

$ rename -v 's/^(file_)(\d+)(\.csv)$/$1 . (sprintf "%02i", $2 + 1) . $3/e' file_*
file_1.csv renamed as file_02.csv
file_2.csv renamed as file_03.csv
file_3.csv renamed as file_04.csv
file_4.csv renamed as file_05.csv
file_5.csv renamed as file_06.csv
file_6.csv renamed as file_07.csv
file_7.csv renamed as file_08.csv
file_8.csv renamed as file_09.csv
file_9.csv renamed as file_10.csv

最後の2つのファイル名を参照してください。

file_09.csv
file_10.csv

答え1

Perlの正規表現修飾子を使用して、/e操作の右側をs///Perl式として評価する必要があります。

ファイル名もソートする必要があります。キャンセル最も高い番号のファイル名を変更するための番号の順序今後低い番号のファイル名(それ以外の場合はファイル名の競合が発生します。デフォルトでは、これを行うには、NUL終了入力に-fGNU renamewithfind-print0GNU sortwithを使用し、リバースバージョン(つまり「自然」)ソートを使用します。フィールドの並べ替えにも使用されます。-z-r-V-t _-k 2

[名前の変更]オプションを-d使用すると、パス名のファイル名部分のみが名前変更され、-0標準入力でNULで区切られたファイルのリストが使用されます。

例えば

$ touch file.csv file_{1..8}.csv
$ find . -name 'file_*.csv' -print0 |
    sort -z -t _ -k2 -r -V |
    rename -d -0 's/^(file_)(\d+)(\.csv)$/$1 . ($2 + 1) . $3/e'
$ mv file.csv file_1.csv
$ ls -l
total 5
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_1.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_2.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_3.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_4.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_5.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_6.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_7.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_8.csv
-rw-r--r-- 1 cas cas 0 Aug 21 15:22 file_9.csv

これは少し簡単になるかもしれませんが、ファイル名file_を変更しないでください。.csv

ファイル番号をゼロで埋めるには、このsprintf機能を使用します。例えば

... | rename -0 -d -v 's/^(file_)(\d+)(\.csv)$/$1 . (sprintf "%02i", $2 + 1) . $3/e'
Reading filenames from file handle (GLOB(0x555555905960))
./file_8.csv renamed as ./file_09.csv
./file_7.csv renamed as ./file_08.csv
./file_6.csv renamed as ./file_07.csv
./file_5.csv renamed as ./file_06.csv
./file_4.csv renamed as ./file_05.csv
./file_3.csv renamed as ./file_04.csv
./file_2.csv renamed as ./file_03.csv
./file_1.csv renamed as ./file_02.csv

答え2

そしてzsh

$ autoload -Uz zmv # best in ~/.zshrc
$ LC_ALL=C zmv -f -n '(file)(|_(<->))(.csv)(#qnOn)' '${1}_$(($3+1))$4'
mv -- file_11.csv file_12.csv
mv -- file_10.csv file_11.csv
mv -- file_9.csv file_10.csv
mv -- file_8.csv file_9.csv
mv -- file_7.csv file_8.csv
mv -- file_6.csv file_7.csv
mv -- file_5.csv file_6.csv
mv -- file_4.csv file_5.csv
mv -- file_3.csv file_4.csv
mv -- file_2.csv file_3.csv
mv -- file_1.csv file_2.csv
mv -- file.csv file_1.csv

または、0-paddingを使用して${(l[2][0])...}左側のパディングパラメータを使用してフラグを拡張します。

$ LC_ALL=C zmv -fn '(file)(|_(<->))(.csv)(#qnOn)' '${1}_${(l[2][0])$(($3+1))}$4'
mv -- file_11.csv file_12.csv
mv -- file_10.csv file_11.csv
mv -- file_9.csv file_10.csv
mv -- file_8.csv file_09.csv
mv -- file_7.csv file_08.csv
mv -- file_6.csv file_07.csv
mv -- file_5.csv file_06.csv
mv -- file_4.csv file_05.csv
mv -- file_3.csv file_04.csv
mv -- file_2.csv file_03.csv
mv -- file_1.csv file_02.csv
mv -- file.csv file_01.csv

(可能であれば削除-n(試運転))。

これにより、このglobで生成されたファイルの名前が変更されます。extendedglobここで:

  • <->一連の数字と一致します(<x-y>指定された範囲なしで演算子と一致する10進整数)。
  • (#q...)次のようにglob修飾子を指定します。
    • n: 数値グローバルソートの切り替え
    • On:名前に基づいて逆順にソートします。だからfile8before file7、上記のNumericglobsortのおかげでfile10before file9。これはLC_ALL=C、ソートアルゴリズムで合計が無視されないようにするためです_.file.csvfile_1.csv

代替では$1、...にはin演算子に似たパターンで$2各ペアの一致が含まれます。()perls///

-fは、健全性チェックを無効にするために使用されます。つまり、既に存在する項目に名前が変更されたことzmvについて文句を言います (それまで既に名前が変更された場合でも)。file6.csvfile7.csvfile7.csvfile8.csv

renamePerlを使用して名前を変更できますが、zsh正しい順序でリストを渡すには、globのようなものがまだ必要です。

$ (LC_ALL=C; rename -f -n '
    s{^(file)(?:_(\d*))?(\.csv)\Z}{
      "${1}_" . (($2 // 0) + 1) . $3}se
   ' file(|_<->).csv(nOn))
rename(file_11.csv, file_12.csv)
rename(file_10.csv, file_11.csv)
rename(file_9.csv, file_10.csv)
rename(file_7.csv, file_8.csv)
rename(file_6.csv, file_7.csv)
rename(file_5.csv, file_6.csv)
rename(file_4.csv, file_5.csv)
rename(file_3.csv, file_4.csv)
rename(file_2.csv, file_3.csv)
rename(file_1.csv, file_2.csv)
rename(file.csv, file_1.csv)

(($2 // 0) + 1)たとえば、パディングを0に置き換えますsprintf("%02d", ($2 // 0) + 1)

そのファイルがないためインストールできませんが、zshGNUシステムを使用している場合は、bash次のコマンドを使用して正しい順序でファイルをインポートできます。

eval "files=(
  $(
    shopt -s extglob failglob
    export LC_ALL=C
    ls --quoting-style=shell-always -rvd file?(_+([0-9])).csv
   )
)"

ls -rvファイルを逆バージョン順にリストするには、GNUを使用してください。

rename ... "${files[@]}"次に、上記とrename同じコードを使用して名前変更を呼び出します。

ここでは、ファイル名が非常に単純で、一致する他のファイルがないと仮定し、file*.csvデフォルト値を使用して$IFSこれを行うこともできます(まだGNU lsを使用していますが、Bourneに似たシェルを使用します)。

rename ... $(LC_ALL=C ls -rvd file*.csv)

答え3

1つのアプローチは次のとおりです。

set -- file_*.csv

while [ "$#" -gt 0 ]; do
  set -- "$#" "$@"
  mv -- "file_$1.csv" "file_$#.csv"
  shift 2
done

mv file.csv file_1.csv

0 で埋められたファイル名を保持するには、mvステートメントを次のように変更します。

mv -- "file_$1.csv" "$(printf 'file_%02d.csv\n' "$#")"
mv file.csv file_01.csv

コマンドライン引数がめちゃくちゃになることが心配な場合は、関数内でこれをすべて実行してその関数を呼び出すことができます。

関連情報