同じ名前の写真がたくさんあると思いますDSC_20170506_170809.JPEG
。パターンに従うように写真の名前を変更するために完全Paris_20170506_170809.JPEG
に機能する次のスクリプトを作成しました。
for file in *.JPEG; do mv ${file} ${file/DSC/Paris}; done
私の質問は、ループのwhile
代わりにループを使用してfor
このスクリプトをどのように書くことができるかということです。
答え1
ここでは、ループの使用に問題はありませんwhile
。あなたはそれを正しくする必要があります:
set -- *.jpeg
while (($#)); do
mv -- "${1}" "${1/DSC/Paris}"
shift
done
上記のループはwhile
ループと同じくらい安定しておりfor
(すべてのファイル名で動作します)、後者が多い場合に使用するのに最適なツールですが、前者は用途がある有効な代替手段です(例:上記の3つ
これらすべてのコマンド(set
、、while..do..done
およびshift
)はシェルマニュアルに文書化されており、その名前は説明を必要としません。
set -- *.jpeg
# set the positional arguments, i.e. whatever that *.jpeg glob expands to
while (($#)); do
# execute the 'do...' as long as the 'while condition' returns a zero exit status
# the condition here being (($#)) which is arithmetic evaluation - the return
# status is 0 if the arithmetic value of the expression is non-zero; since $#
# holds the number of positional parameters then 'while (($#)); do' means run the
# commands as long as there are positional parameters (i.e. file names)
mv -- "${1}" "${1/DSC/Paris}"
# this renames the current file in the list
shift
# this actually takes a parameter - if it's missing it defaults to '1' so it's
# the same as writing 'shift 1' - it effectively removes $1 (the first positional
# argument) from the list so $2 becomes $1, $3 becomes $2 and so on...
done
1: テキスト処理ツールに代わるものではないのでいいえループを使用してwhile
テキストを処理します。
答え2
for
-ループは通常再び完了します。変化のないデータ。つまり、ループ中または既知の時間間隔内でデータは変更されません。
while
ループは、ユーザーに入力を要求し、正確になるまで応答を検証したり、ファイルやパイプから読み取ったデータを繰り返すなど、繰り返しが必要な回数がわからない場合によく使用されます。
この場合、シェルの拡張ファイルグロービングパターンに従って、現在のディレクトリから直接読み取ったファイル名を繰り返します。ループはfor
正しく使用されるループ構造です。ループはwhile
状況を複雑にし、コードを正しく読み取って実行するのを困難にします。
以下は、while
ループと同じ操作を実行するループの例ですfor
。
printf '%s\n' DSC*.JPEG |
while read -r name; do
[ ! -f "Paris${name#DSC}" ] && mv "$name" "Paris${name#DSC}"
done
ここに何か問題があります。
- ループは改行で区切られた名前を読み取るため、ファイル名に改行を含めることはできません。
printf
出力で\0
区切られたファイル名を取得してread
読み込むと、この問題を解決できますが、これにより問題がより複雑になり、移植性が低下します。 - 何も得られませんでした。名前リストはまだ静的であり、これらの名前を
printf
ループに渡す冗長ステップを導入しました。これにより、ファイル名にどの文字を許可できるかについての質問が発生します(前のトピックを参照)。
実際、コードの唯一の問題は、変数拡張が引用されていないことです。
答え3
until
必要に応じて、Bashループを使用することもできます。
set -- *.jpeg
until ((! $#))
do
mv -- "${1}" "${1/DSC/Paris}"
shift
done