次の形式で多数のファイル名を変更する必要がある状況が発生しました。
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終了入力に-f
GNU rename
withfind
と-print0
GNU sort
withを使用し、リバースバージョン(つまり「自然」)ソートを使用します。フィールドの並べ替えにも使用されます。-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
:名前に基づいて逆順にソートします。だからfile8
beforefile7
、上記のNumericglobsortのおかげでfile10
beforefile9
。これはLC_ALL=C
、ソートアルゴリズムで合計が無視されないようにするためです_
。.
file.csv
file_1.csv
代替では$1
、...にはin演算子に似たパターンで$2
各ペアの一致が含まれます。(
)
perl
s///
-f
は、健全性チェックを無効にするために使用されます。つまり、既に存在する項目に名前が変更されたことzmv
について文句を言います (それまで既に名前が変更された場合でも)。file6.csv
file7.csv
file7.csv
file8.csv
rename
Perlを使用して名前を変更できますが、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)
。
そのファイルがないためインストールできませんが、zsh
GNUシステムを使用している場合は、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
コマンドライン引数がめちゃくちゃになることが心配な場合は、関数内でこれをすべて実行してその関数を呼び出すことができます。