私は私のシェルで同じループ内の2つのシーケンスを次のように実行しようとしています:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
どうすればこれを達成できますか?
そのためにはブレースの拡張のみが必要です
$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203
リストをfor
(for i in x y z; do stuff "$i"; done
)に渡すことができます。
したがって、ここでは、中括弧{
}
を使用して、シーケンスをリストに展開するシェルを取得します。シェルはそれらの引数のリストを分割するため、それらの間にスペースを入れるだけです。
または、seq
(数字のシーケンスを印刷)を使用することもできます。これは2つの同等の例です。
for i in `seq 1 3` `seq 101 103`; do echo $i; done
for i in $(seq 1 3) $(seq 101 103); do echo $i; done
スクリプトの場合、反復タスクの場合、次の関数を使用できます。
#!/bin/bash
my_function() { echo "$1"; }
for i in {1..3}; do my_function "$i"; done
for i in {101..103}; do my_function "$i"; done
#!/bin/bash
my_function() { for i in `seq $1 $2`; do echo "$i"; done; }
my_function "1" "3"
my_function "101" "103"
Zannaの答えは絶対に正確であり、bashに適していますが、ループを使用せずにさらに改善できます。
printf "%d\n" {1..15} {20..25}
printf
の動作は、ARGUMENTS
の数が'FORMAT STRING'
のフォーマットコントロールよりも大きい場合、printf
はすべてのARGUMENTS
を等しいチャンクに分割して保持します。 ARGUMENTS
リストを使い果たすまで、フォーマット文字列に繰り返しフィットさせます。
移植性に努めている場合は、代わりにprintf "%d\n" $(seq 1 15) $(seq 20 25)
を利用できます
これをさらにもっと楽しくしてみましょう。単に数字を印刷するのではなく、アクションを実行したいとします。その一連の番号からファイルを作成する場合、touch {1..15}.txt {20..25}.txt
を簡単に実行できます。複数のことを発生させたい場合はどうしますか?次のようなこともできます。
$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %
または、古いスタイルにしたい場合:
printf "%d\n" {1..15} {20..25} | while read -r line; do
touch "$line".txt;
stat "$line".txt;
rm "$line".txt;
done
ブレース展開のないシェル({1..15} {20..25}
が依存するもの)で動作するスクリプトソリューションを作成する場合、単純なwhileループを記述できます。
#!/bin/sh
start=$1
jump=$2
new_start=$3
end=$4
i=$start
while [ $i -le $jump ]
do
printf "%d\n" "$i"
i=$((i+1))
if [ $i -eq $jump ] && ! [ $i -eq $end ];then
printf "%d\n" "$i"
i=$new_start
jump=$end
fi
done
もちろん、この解決策はより冗長であり、短くすることもできますが、うまくいきます。 ksh
、dash
、mksh
、およびもちろんbash
でテスト済み。
しかし、ループをbash固有にしたい場合(何らかの理由で、単に印刷するだけでなく、それらの数字で何かをすることもあります)、これも行うことができます(基本的にはCループバージョンのポータブルソリューション)。
last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done
または、より読みやすい形式で:
last=15
for (( i=1; i<=last;i++ ));
do
printf "%d\n" "$i"
[[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;}
done
bash-4.3$ time bash -c 'printf "%d\n" {0..50000}>/dev/null'
real 0m0.196s
user 0m0.124s
sys 0m0.028s
bash-4.3$ time bash -c 'for i in {1..50000}; do echo $i > /dev/null; done'
real 0m1.819s
user 0m1.328s
sys 0m0.476s
bash-4.3$ time bash -c ' i=0;while [ $i -le 50000 ]; do echo $i>/dev/null; i=$((i+1)); done'
real 0m3.069s
user 0m2.544s
sys 0m0.500s
bash-4.3$ time bash -c 'for i in $(seq 1 50000); do printf "%d\n" > /dev/null; done'
real 0m1.879s
user 0m1.344s
sys 0m0.520s
ここにPythonソリューションがあるからといって
$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'
または、少しのシェルで:
bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
> print(i)
> EOF