私はスクリプト(bashシェル)に最初に触れましたが、私がやろうとしているこのタスクのロジックを理解できません。
たとえば、次のファイル名を持つフォルダがあります。
PIC-100
PIC-1
PIC-23
PIC-5
ファイル名から番号を取得し、最も低いものから高いものまでランク付けし、ランクリストの場所に基づいて名前を変更できるようにしたいです。
たとえば、名前は次のように変更されます。
PIC-100 --> PIC-4
PIC-1 --> PIC-1
PIC-23 --> PIC-3
PIC-5 --> PIC-2
みんなありがとうございます。
答え1
この問題を解決する方法を段階的に説明します。まず、いくつかのテストデータを作成しましょう。
mkdir /tmp/blah && cd /tmp/blah
for f in 1 90 $RANDOM $RANDOM $RANDOM; do touch PIC-$f; done
ls
ファイルは名前でソートする必要がありますが、私たちは数字でソートしたいと思います。このコマンドは、sort
この問題を解決するのに役立ちます。
ls | sort -V
-V
お客様の場合に適した「バージョン別注文」を意味します。他のオプションについてはを参照してくださいman sort
。
今、名前を変更します。これを行う方法はいくつかありますが、ソートされたリストの出力を繰り返します。変数とループが必要です。
counter=1 ls PIC-* | sort -V | while read fname; do
echo mv -i "$fname" NEWPIC-$counter
let counter+=1
done
ここには多くのことが起こっているので安全から詳しく説明します。まず、ファイルのバックアップ続行する前に、屋根ふきは簡単に間違っているため、悪い日につながる可能性があります。すべてをバックアップするコマンドは次のとおりです。
mkdir backup; cp PIC* backup
このループで問題が発生すると混乱する可能性があるので、ループを実行する前に何が起こるのかを確認したかったのです。知ってるecho
?これにより、予想されるコマンドを実行する代わりに印刷されます。出力を削除echo
またはコピーして貼り付けて、「実際に」コマンドを実行できます。
次に、mv -i
名前変更のために戦い始めました。私が何かをカバーするならば、これは暗示されます。その頃なら、すべてがとにかく船の形になったはずですが、少なくとも私はわかります。
第三に、名前PIC-xxx
をNEWPIC-xxx
。これは本当に重要場合によっては、誤ってPIC-3の名前をPIC-2に変更する可能性があります(たとえば、何らかの理由でPIC-2.5が存在する場合)。NEW
このセクションは後で整理できます。
また、startコマンドを使用しますcounter=1 ls | sort -V | ...
。変数を設定して存在するテスト実行間の設定を忘れたときに「奇妙な」動作が表示されるのを防ぐためのコマンド - ターゲットファイル名は、次のようにNEWPIC-6
始まりますNEWPIC-1
。これは何度も間違えた後に得られる習慣の一つです。
それでは、ループ自体について話しましょう。
while read fname
「入力行を表示するたびに、その行を変数に入れてfname
次の部分を実行してください。do .. done
各行に対して実行したいコードを囲みます。echo mv -i "$fname" NEWPIC-$counter
実行したいコマンドを印刷します。let counter+=1
カウンター変数を増やします。これを忘れた場合、最終的には1つのファイルが呼び出され、NEWPIC-1
残りのファイルはすべて消えます。だから私たちはバックアップを持っています:)
NEW
最後に、ファイル名の先頭から削除するいくつかのトリックは次のとおりです。
for fname in NEWPIC-*; do echo mv $fname ${fname#NEW}; done
echo
以前と同様に、出力が満足のいくものであれば削除してください。
答え2
この注釈付きのシェルスクリプトは、必要な操作を実行します。セミコロンはコマンドの順次実行を表し、垂直バーはパイプラインを表し、ポンド記号はコメントを開始し、「do-done」ペアは「while」に含まれるループを表します。
n=1 ; # initialize counter
ls | # list current working directory
sort -V | # sort (thanks to dwurf for the flag, but this isn't in POSIX standard yet)
while read f ; do
mv "$f" PIC-$n ; # rename file
n=$((n+1)) ; # counter increment.
done
答え3
zsh
シェルの使用:
tmpdir=$(mktemp -d)
n=1
for name in PIC-*(.n); do
mv $name $tmpdir/PIC-$(( n++ ))
done
mv $tmpdir/PIC-* .
rmdir $tmpdir
これにより、現在のディレクトリで名前が一致するすべての一般ファイルを一時PIC-*
ディレクトリに移動し、名前を変更します。ファイルは、ファイル名の番号に基づいてソートされた番号順に移動されます(これはglob修飾子がn
実行する操作です(.n)
。.
通常のファイルのみが選択されます)。各ファイルのカウンタがあるPIC-n
場所でファイル名が変更されます。n
すべてのファイルを移動して名前を変更すると、現在のディレクトリに戻り、一時ディレクトリは削除されます。
名前の競合を避けるために、一時ディレクトリを準備領域として使用してください。
何千ものファイルがある場合は、mv
「引数リストが多すぎる」エラーを防ぐために、ループ内で2番目のファイルを実行する必要があります。
# first loop as before, then...
for name in $tmpdir/PIC-*; do
mv $name .
done
rmdir $tmpdir
cp
最後にファイルの代わりにファイルがある場合は、「逆順」で実行すると、一時ディレクトリにファイルの元の名前がバックアップされます。mv
tmpdir=$(mktemp -d)
mv PIC-*(.) $tmpdir
n=1
for name in $tmpdir/PIC-*(n); do
# change "mv" to "cp" (and remove "rmdir" below)
# to leave a copy in the temporary directory
mv $name PIC-$(( n++ ))
done
rmdir $tmpdir