Estoy tratando de ejecutar dos secuencias en el mismo bucle en mi shell como a continuación:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
¿Alguna idea de cómo puedo lograr esto?
Estoy tratando de ejecutar dos secuencias en el mismo bucle en mi shell como a continuación:
#!/bin/bash
for i in (1..15) and (20..25) ;
do
echo $i
......
.....other process
done
¿Alguna idea de cómo puedo lograr esto?
Respuestas:
Solo necesitas expansión de llaves para eso
$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203
Podemos pasar una lista a for
( ).for i in x y z; do stuff "$i"; done
Entonces, aquí, las llaves {
}
obtienen el shell para expandir sus secuencias en una lista. Solo necesita poner un espacio entre ellos, ya que el shell divide listas de argumentos sobre ellos.
echo
los números
touch
archivos, simplemente pueden hacer touch {1..15}.txt {20..25}.txt
, no se necesita un bucle aquí. Pero, por supuesto, si se trata de múltiples acciones en el mismo número, está bien, eso podría usar un bucle.
Alternativamente, podemos usar seq
( imprimir una secuencia de números ), aquí hay dos ejemplos equivalentes:
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
Si es un script, para tareas repetitivas, puede usar funciones:
#!/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 respuesta de Zanna y respuesta de pa4080 son buenos y probablemente iría con uno de ellos en la mayoría de las circunstancias. Quizás no hace falta decirlo, pero en aras de la exhaustividad, lo diré de todos modos: puede cargar cada valor en una matriz y luego recorrerla en bucle. Por ejemplo:
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 respuesta de Zanna es absolutamente correcta y adecuada para bash, pero podemos mejorar eso aún más sin utilizar un bucle.
printf "%d\n" {1..15} {20..25}
El comportamiento de printf
es tal que si el número de ARGUMENTS
es mayor que los controles de formato 'FORMAT STRING'
, printf
los dividirá ARGUMENTS
en trozos iguales y los ajustará a la cadena de formato una y otra vez hasta que se agote la ARGUMENTS
lista.
Si nos esforzamos por la portabilidad, podemos utilizar en su printf "%d\n" $(seq 1 15) $(seq 20 25)
lugar
Llevemos esto más lejos y más divertido. Digamos que queremos realizar una acción en lugar de solo imprimir números. Para crear archivos a partir de esa secuencia de números, podríamos hacerlo fácilmente touch {1..15}.txt {20..25}.txt
. ¿Qué pasa si queremos que ocurran varias cosas? También podríamos hacer algo como esto:
$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %
O si queremos hacerlo al estilo de la vieja escuela:
printf "%d\n" {1..15} {20..25} | while read -r line; do
touch "$line".txt;
stat "$line".txt;
rm "$line".txt;
done
Si queremos crear una solución de script que funcione con shells que no tengan expansión de llaves (que es de lo que {1..15} {20..25}
depende), podemos escribir un ciclo while simple:
#!/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
Por supuesto, esta solución es más detallada, algunas cosas podrían acortarse, pero funciona. Probado con ksh
, dash
, mksh
, y, por supuesto bash
.
Pero si quisiéramos hacer un ciclo específico de bash (por cualquier razón, quizás no solo imprimiendo sino también haciendo algo con esos números), también podemos hacer esto (básicamente la versión C-loop de la solución portátil):
last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done
O en formato más legible:
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
Solo porque podemos, aquí está la solución de Python
$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'
O con un poco de concha:
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
usted ni siquiera necesita $()
allí, solo touch {1..15}.txt {20..25}.txt
:) Pero, por supuesto, podríamos usar printf "%d\n
{1..15} {20..25} ` xargs
si quisiéramos hacer más que solo touch
archivos. ¡Hay muchas maneras de hacer las cosas y hace que las secuencias de comandos sean muy divertidas!