J'essaie de parcourir deux séquences dans la même boucle dans mon shell comme ci-dessous:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
une idée comment je peux y arriver?
J'essaie de parcourir deux séquences dans la même boucle dans mon shell comme ci-dessous:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
une idée comment je peux y arriver?
Réponses:
Vous avez seulement besoin d'une extension de soutien pour cela
$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203
Nous pouvons passer une liste à for
( ).for i in x y z; do stuff "$i"; done
Donc, ici, les accolades {
}
obtiennent le shell pour développer vos séquences dans une liste. Vous avez seulement besoin de mettre un espace entre eux, car le shell divise les listes d'arguments sur ceux-ci.
echo
les chiffres
touch
fichiers, ils peuvent le faire touch {1..15}.txt {20..25}.txt
, aucune boucle n'est nécessaire ici. Mais bien sûr, si c'est plusieurs actions sur le même numéro - OK, cela pourrait utiliser une boucle.
Alternativement, nous pouvons utiliser seq
( imprimer une séquence de nombres ), voici deux exemples équivalents:
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
S'il s'agit d'un script, pour des tâches répétitives, vous pouvez utiliser des fonctions:
#!/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"
La réponse de Zanna et la réponse de pa4080 sont à la fois bien et je serais probablement aller avec l' un d'eux dans la plupart des cas. Cela va peut-être de soi, mais pour être complet, je le dirai quand même: vous pouvez charger chaque valeur dans un tableau puis boucler sur le tableau. Par exemple:
the_array=( 1 2 3 4 5 6 7 8 9 10 20 21 22 23 24 25 )
for i in "${the_array[@]}";
do
echo $i
done
La réponse de Zanna est absolument correcte et bien adaptée à bash, mais nous pouvons encore améliorer cela sans utiliser de boucle.
printf "%d\n" {1..15} {20..25}
Le comportement de printf
est tel que si le nombre de ARGUMENTS
est supérieur aux contrôles de format 'FORMAT STRING'
, alors tout printf
sera divisé ARGUMENTS
en morceaux égaux et continuera de les ajuster à la chaîne de formatage jusqu'à ce qu'il soit épuisé ARGUMENTS
.
Si nous recherchons la portabilité, nous pouvons utiliser à la printf "%d\n" $(seq 1 15) $(seq 20 25)
place
Allons plus loin et plus amusant. Disons que nous voulons effectuer une action plutôt que d'imprimer simplement des nombres. Pour créer des fichiers à partir de cette séquence de nombres, nous pourrions facilement le faire touch {1..15}.txt {20..25}.txt
. Et si nous voulons que plusieurs choses se produisent? Nous pourrions également faire quelque chose comme ceci:
$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %
Ou si nous voulons le faire à l'ancienne:
printf "%d\n" {1..15} {20..25} | while read -r line; do
touch "$line".txt;
stat "$line".txt;
rm "$line".txt;
done
Si nous voulons créer une solution de script qui fonctionne avec des shells qui n'ont pas d'expansion d'accolade (ce {1..15} {20..25}
sur quoi repose), nous pouvons écrire une simple boucle 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
Bien sûr, cette solution est plus verbeuse, certaines choses pourraient être raccourcies, mais cela fonctionne. Testé avec ksh
, dash
, mksh
et, bien sûr bash
.
Mais si nous voulions créer une boucle spécifique à bash (pour une raison quelconque, peut-être pas seulement en imprimant mais aussi en faisant quelque chose avec ces nombres), nous pouvons également le faire (essentiellement une version en boucle C de la solution portable):
last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done
Ou dans un format plus lisible:
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
Tout simplement parce que nous pouvons voici la solution Python
$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'
Ou avec un peu de coquille:
bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
> print(i)
> EOF
touch $(printf "%d\n" {1..15} {20..25})
:-)
bash
vous n'en avez même pas besoin $()
, juste touch {1..15}.txt {20..25}.txt
:) Mais bien sûr, nous pourrions utiliser printf "%d\n
{1..15} {20..25} `avec xargs
si nous voulions faire plus que de simples touch
fichiers. Il y a plusieurs façons de faire les choses et cela rend le script tellement amusant!