
だから私はこれをしようとします。
for x in {1..7000}
do
echo $x
done
出力は次のとおりです{1..7000}
また、Cスタイルのforループがmkshでは機能しないことも学びました。
私はいくつかのインターネット検索をしましたが、ほとんどはmkshではなくkshに関する情報です。
もしそうなら、mkshで範囲を繰り返す正しい方法は何ですか?
メモ:私は文字列を印刷するよりも繰り返しとCと同様の動作を生成する正しい方法に興味があります。
答え1
ではまず、現状のままここで簡単に議論しました一般的なフォーム...
for arg in {brace..expanded..set}; do ...
...私の考えでは、これがシェルプログラミングエラーの代表的な例です。ループから数式セットを作成し、各結果を区切り配列に保存してから次に渡します。別のループ配列を繰り返すリストとして表します。
通常、角かっこ拡張はプログラミング環境では特に有用ではありません。すべてのシェルプログラミングは何らかの方法でマクロそして支柱の拡張すでにマクロです。支柱の拡張は(私も思う)ㅏとても役に立つ対話型シェル機能はマクロなので便利です。それ以外の場合は無駄になります。
サポート拡張も移植可能ではありません。(読む:POSIX - ポータブル)。私が知っている限り、通常は現在のバージョンの、、、、zsh
ではbash
動作できますが、yash
他の場所では動作しません。これらのシェルでもシェルオプションを使用して無効にすることができるため、通常はまたは出力で可用性をテストできますが、シェル機能の文脈にksh93
絶対に依存することはできません。その間に上記のシェルのそれぞれには異なる種類のテストが必要ですので、これを関数に使ってテストしたい場合は、ターゲットシェルのマニュアルで具体的な内容を確認してください。$-
set +o
他のシェルでは、コマンド置換の出力を分割してほぼ同じ動作を得ることができます。ただし、コレクションを作成するには外部実行可能ファイルを呼び出す必要がある点だけが異なります$IFS
。これはプログラムがseq
利用可能な場所で簡単に実証されています。例えば…
unset IFS
### ^ensure $IFS default behavior
for arg in $(seq 7000)
do printf %d\\n "$arg"
done
...または...
unset IFS
printf %d\\n $(seq 7000)
...しかし、書かれているように、どちらも欠点以外には何も提供しません...
seq 7000
ただし、最初の例では、メソッドは中括弧拡張バージョンとほぼ同じです。どちらの場合も、他のいくつかの関数またはプロセスは完全な引数リストを生成し、コントロールfor
コンストラクタによって繰り返されます。しかし、後者の場合、(その他のシェルのksh93
場合パイプを開く/解体もあり、シェルプロセスとそのサブプロセスを分岐し、seq
最後に$IFS
。
$IFS
しかし、分割は使用されているシェルに応じて非常に異なる速度で発生します。bash
たとえば、単純な$IFS
分割パフォーマンスはしばしば不都合ですが、dash
分割文字列の行の長さに応じて、中かっこ拡張を実行する他のシェルほど速くなる可能性があります。
ただし、中かっこ拡張を使用しても分割を使用しても、$IFS
最終結果はいくつかのループを実行して数式リストを生成し、別のループを実行してそのリストを繰り返すことです。代わりに、あなたがすることができ、おそらくやるべきことは、リストを生成した式の適用に対してループを実行し、使用されたイテレータをできるだけ早く処理し、満足のいく結果を得るために各イテレーションをテストすることです。 Cではこんなことをします...
for ( x = 0; x < 10; x++ ){ ...
これは、実際に行うことができる操作に似ているか、またはでbc
使用できる便利な構文形式と非常によく似ています。ksh93
zsh
bash
for (( x=0; x<10; x++ )); do ...
しかし、これもポータブルではありません。(もう一度読む:POSIX)。代わりに、以下を移植可能に実行できます。
iterator=$(( start_value - interval ))
while [ "$(( iterator += interval ))" -le "$end_value" ]; do ...
...または...
iterator=$(( start_value - interval ))
while [ "$(( ( iterator += interval ) <= end_value ))" -ne 0 ]; do ...
POSIXの指定C算術演算(つまり、整数が含まれている場合)のシェル算術拡張と機能パリティチェックに似ています。その結果、単一の拡張で複雑な数式を便利かつ移植可能に繰り返すことができ、複数の変数を同時に同時に繰り返すこともできます。
一方、これらの構成は、他のC言語とシェル言語の不平等を解決するのが難しくなります。シェルの読み書きはほとんど常にリテラルsとs(各システムコール自体)であり、read()
シェル構文には移植可能および/またはアナログはwrite()
ありません。したがって、各反復でこれらのタスクを実行するループは(このタスクを実行するために組み込み関数のみを使用しても)パフォーマンスの低下を招く可能性があります。fread()
fwrite()
setbuf()
しかし、時にはシェルスクリプトからコレクション全体を順次または並列に構築して実行することの間で妥協を見つけることができます。
set 0 1 2 3 4 5 6 7 8 9
for n do printf "$n%d\n" "$@"; done
これはwrite()
10回繰り返して10回実行され、00から99の間に改行で区切られたシーケンスを印刷します。これは非常に小さな例であり、まだ無駄です。 30バイトwrite()
は3バイトに比べて大幅に改善されていないからです。write()
しかし、これはあなたが利用できるこのタイプのアプローチを示しています。前述したように、シェルプログラミング言語は非常に便利です。マクロ内部にすべては文字列です。したがって、ターゲットセットをより小さく管理しやすいセットに分割し、ループコンテキストで繰り返し呼び出して最終的にターゲットセットを作成できる場合は、よりパフォーマンスの良い結果が得られることがよくあります。
以下は、より複雑でマクロに似た例です。
sh -c '
i=0 _i=-25
set "$1" "$1" "$1" "$1" "$1"
for n do eval "
printf %b%d $@ $@ $@ $@ $@"
done' -- \
'"\01$((1+(i<(i+=!(_i=(_i+=25)%275)))))" "$i$_i"'
write()
それぞれ平均約100バイトに対して5回繰り返し、次のものを印刷します。
10 125 150 175 1100 1125 1150 1175 1200 1225 1250
20 225 250 275 2100 2125 2150 2175 2200 2225 2250
30 325 350 375 3100 3125 3150 3175 3200 3225 3250
40 425 450 475 4100 4125 4150 4175 4200 4225 4250
50 525 550 575 5100 5125 5150 5175 5200 5225 5250
60 625 650 675 6100 6125 6150 6175 6200 6225 6250
70 725 750 775 7100 7125 7150 7175 7200 7225 7250
80 825 850 875 8100 8125 8150 8175 8200 8225 8250
90 925 950 975 9100 9125 9150 9175 9200 9225 9250
100 1025 1050 1075 10100 10125 10150 10175 10200 10225 10250
110 1125 1150 1175 11100 11125 11150 11175 11200 11225 11250
120 1225 1250 1275