¿Cómo escribo un bucle for en bash?

Respuestas:

103

De este sitio :

for i in $(seq 1 10);
do
    echo $i
done
Rob Rolnick
fuente
10
Vale la pena mencionar que el rango especificado aquí es inclusivo . Con eso, quiero decir que verá el rango completo (1 a 10) impreso en la consola.
Jamie
62
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
Nick Stinemates
fuente
si tenemos una variable como ArrayLength=${#array[@]}¿cómo la usamos aquí en lugar de max?
Kasun Siyambalapitiya
34

El bash forconsiste en una variable (el iterador) y una lista de palabras donde el iterador, bueno, iterará.

Entonces, si tiene una lista limitada de palabras, simplemente colóquelas en la siguiente sintaxis:

for w in word1 word2 word3
do
  doSomething($w)
done

Probablemente desee iterar a lo largo de algunos números, por lo que puede usar el seqcomando para generar una lista de números para usted: (de 1 a 100 por ejemplo)

seq 1 100

y utilícelo en el bucle FOR:

for n in $(seq 1 100)
do
  doSomething($n)
done

Tenga en cuenta la $(...)sintaxis. Es un comportamiento bash, le permite pasar la salida de un comando (en nuestro caso desde seq) a otro (el for)

Esto es realmente útil cuando tiene que iterar sobre todos los directorios en alguna ruta, por ejemplo:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

Las posibilidades son infinitas para generar las listas.

Fernando Barrocal
fuente
2
Buena respuesta, pero es posible que desee incluir for ((i = 0; i <MAX; i ++)); hacer algo ($ i); variante hecha también. Creo que esto generalmente se prefiere a la variante for i en $ (seq 0 MAX), ya que esta última generará primero todos los números de 0 a MAX antes de ejecutar el ciclo.
mweerden
30

Bash 3.0+ puede usar esta sintaxis:

for i in {1..10} ; do ... ; done

..que evita generar un programa externo para expandir la secuencia (como seq 1 10).

Por supuesto, esto tiene el mismo problema que la for(())solución, está vinculado a bash e incluso a una versión en particular (si esto te importa).

David Gardner
fuente
14

Prueba la bashayuda incorporada:


$ help for

for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.


Pat Notz
fuente
5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

Aquí hay un ejemplo que también puede funcionar en shells más antiguos, sin dejar de ser eficiente para grandes recuentos:

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

Pero buena suerte haciendo cosas útiles dentro de awk: ¿Cómo uso las variables de shell en un script awk?

Brent Bradburn
fuente
2
No lo noté antes, pero se muestra una sintaxis similar en una de las respuestas anteriores. Lo único aquí es el uso de llaves en lugar del típico do/ donepar.
Brent Bradburn
4

Por lo general, me gusta usar una ligera variante del estándar for loop. A menudo uso esto para ejecutar un comando en una serie de hosts remotos. Aprovecho la expansión de llaves de bash para crear bucles for que me permiten crear bucles for no numéricos.

Ejemplo:

Quiero ejecutar el comando de tiempo de actividad en los hosts frontend 1-5 y los hosts backend 1-3:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

Normalmente ejecuto esto como un comando de una sola línea con punto y coma al final de las líneas en lugar de la versión más legible anterior. La consideración clave del uso es que las llaves le permiten especificar múltiples valores para ser insertados en una cadena (por ejemplo, pre {foo, bar} post resultados en prefoopost, prebarpost) y permitir el conteo / secuencias mediante el uso de puntos dobles (puede usar un. .z etc.). Sin embargo, la sintaxis de doble período es una nueva característica de bash 3.0; las versiones anteriores no lo admitirán.

terson
fuente
Relacionado con esto, ¿qué pasa si $ host var es una línea vacía por algún accidente? Todavía dispararía ssh. Entonces, ¿cómo evito eso? En mi caso estoy haciendo algo diferente y por eso tu respuesta me ayudará. Estoy tratando de buscar mensajes nuevos en Gmail y, si los encuentro, enviar un SMS con el remitente y el asunto. Mi pregunta está etiquetada como "Conectando dos comandos Bash" si quieres leerla.
Volomike
No creo que obtengas una $ host var vacía. Esto se debe a que el ejemplo anterior utiliza la expansión de llaves. El bucle for establece explícitamente la variable $ host en valores: frontend1.mycompany.com frontend2.mycompany.com. . backend1.mycompany.com Pero si ve una forma de que tenga un valor nulo; Me interesaría saber. Podría ejecutar ssh dentro de una prueba condicional si fuera una preocupación.
terson
1

si solo está interesado en bash, la solución "for ((...))" presentada anteriormente es la mejor, pero si desea algo compatible con POSIX SH que funcione en todos los sistemas, tendrá que usar "expr" y "while", y eso se debe a que "(())" o "seq" o "i = i + 1" no son tan portátiles entre varios shells


fuente
0

Utilizo variaciones de esto todo el tiempo para procesar archivos ...

para archivos en * .log; hacer eco "Hacer cosas con: $ archivos"; echo "Hacer más cosas con: $ archivos"; hecho;

Si lo que le interesa es procesar listas de archivos, busque los archivos en la opción -execdir .


fuente
Creo que te refieres a la opción -execdir para buscar
pausa hasta nuevo aviso.