FORループの代わりにWHILEループを使用してファイル名を変更する

FORループの代わりにWHILEループを使用してファイル名を変更する

同じ名前の写真がたくさんあると思います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

ここに何か問題があります。

  1. ループは改行で区切られた名前を読み取るため、ファイル名に改行を含めることはできません。printf出力で\0区切られたファイル名を取得してread読み込むと、この問題を解決できますが、これにより問題がより複雑になり、移植性が低下します。
  2. 何も得られませんでした。名前リストはまだ静的であり、これらの名前をprintfループに渡す冗長ステップを導入しました。これにより、ファイル名にどの文字を許可できるかについての質問が発生します(前のトピックを参照)。

実際、コードの唯一の問題は、変数拡張が引用されていないことです。

答え3

until必要に応じて、Bashループを使用することもできます。

set -- *.jpeg
until ((! $#))
do
    mv -- "${1}" "${1/DSC/Paris}"
    shift
done

関連情報