Hay una mejor manera de ejecutar un comando N veces en bash?


Ocasionalmente corro una línea de comandos bash como esta:

n=0; while [[ $n -lt 10 ]]; do some_command; n=$((n+1)); done

Para ejecutar some_command varias veces seguidas 1 10 veces en este caso.

A menudo some_command es realmente una cadena de comandos o una canalización.

¿Hay una manera más concisa de hacer esto?

 220
Author: jww, 2010-09-17

19 answers

for run in {1..10}
do
  command
done
 305
Author: Joe Koberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-17 18:01:50
for ((n=0;n<10;n++)); do some_command; done
 171
Author: BatchyX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-17 18:01:27

Otra forma sencilla de hackearlo:

seq 20 | xargs -Iz echo "Hi there"

Ejecuta echo 20 veces.


Observe que seq 20 | xargs -Iz echo "Hi there z" produciría:

Hola 1
Hola 2
...

 98
Author: mitnk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-27 22:21:57

Si estás usando el shell zsh:

repeat 10 { echo 'Hello' }

Donde 10 es el número de veces que se repetirá el comando.

 48
Author: Wilson Silva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-29 12:42:20

Usando GNU Parallel puedes hacer:

parallel some_command ::: {1..1000}

Si no desea el número como argumento y solo ejecuta un solo trabajo a la vez:

parallel -j1 -N0 some_command ::: {1..1000}

Vea el video de introducción para una introducción rápida: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Recorre el tutorial ( http://www.gnu.org/software/parallel/parallel_tutorial.html ). Usted línea de comandos con amor por ello.

 21
Author: Ole Tange,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-17 22:20:20

Otra forma de tu ejemplo:

n=0; while (( n++ < 10 )); do some_command; done
 10
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-17 19:06:28

xargs es rápido :

#!/usr/bin/bash
echo "while loop:"
n=0; time while (( n++ < 10000 )); do /usr/bin/true ; done

echo -e "\nfor loop:"
time for ((n=0;n<10000;n++)); do /usr/bin/true ; done

echo -e "\nseq,xargs:"
time seq 10000 | xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nyes,xargs:"
time yes x | head -n10000 |  xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nparallel:"
time parallel --will-cite -j1 -N0 /usr/bin/true ::: {1..10000}

En un Linux moderno de 64 bits, da:

while loop:

real    0m2.282s
user    0m0.177s
sys     0m0.413s

for loop:

real    0m2.559s
user    0m0.393s
sys     0m0.500s

seq,xargs:

real    0m1.728s
user    0m0.013s
sys     0m0.217s

yes,xargs:

real    0m1.723s
user    0m0.013s
sys     0m0.223s

parallel:

real    0m26.271s
user    0m4.943s
sys     0m3.533s

Esto tiene sentido, ya que el comando xargs es un único proceso nativo que genera el comando /usr/bin/true varias veces, en lugar de los bucles for y while que se interpretan en Bash. Por supuesto, esto solo funciona para un solo comando; si necesita hacer varios comandos en cada iteración del bucle, será igual de rápido, o tal vez más rápido, que pasar sh -c 'command1; command2; ...' a xargs

El -P1 también se podría cambiar a, por ejemplo, -P8 para generar 8 procesos en paralelo para obtener otro gran impulso en la velocidad.

No entiendo por qué GNU parallel es tan lento. Habría pensado que sería comparable a Xargs.

 9
Author: James Scriven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-05 18:38:42

Una función simple en el archivo de configuración de bash (.bashrc para mí, en un Mac) podría funcionar bien.

function runx() {
  for ((n=0;n<$1;n++))
    do ${*:2}
  done
}

Llámalo así.

$ runx 3 echo 'Hello world'
Hello world
Hello world
Hello world
 9
Author: steel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-29 14:52:30

Xargs y seq ayudarán

function __run_times { seq 1 $1| { shift; xargs -i -- "$@"; } }

La vista:

abon@abon:~$ __run_times 3  echo hello world
hello world
hello world
hello world
 7
Author: firejox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-26 16:21:02
for _ in {1..10}; do command; done   

Tenga en cuenta el subrayado en lugar de usar una variable.

 5
Author: Ali Omary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-12 23:04:11

Para uno, puede envolverlo en una función:

function manytimes {
    n=0
    times=$1
    shift
    while [[ $n -lt $times ]]; do
        $@
        n=$((n+1))
    done
}

Llámalo como:

$ manytimes 3 echo "test" | tr 'e' 'E'
tEst
tEst
tEst
 4
Author: bta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-17 18:06:27

Si está bien hacerlo periódicamente, puede ejecutar el siguiente comando para ejecutarlo cada 1 segundo indefinidamente. Puede poner otras comprobaciones personalizadas en su lugar para ejecutarlo n número de veces.

watch -n 1 some_command

Si desea tener confirmación visual de los cambios, añada --differences antes del comando ls.

De acuerdo con la página man de OSX, también hay

La opción cumulative cumulative hace que el resaltado sea "pegajoso", presentando un visualización de todas las posiciones que tienen nunca cambió. The-t o la opción no no-title desactiva el encabezado que muestra el intervalo, comando, y la hora actual en la parte superior de la pantalla, así como siguiendo una línea en blanco.

La página de manual de Linux/Unix se puede encontrar aquí

 2
Author: Pankaj Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-07 08:42:40

Todas las respuestas parecen exigir bash, y no trabajar con un estándar de BSD UNIX /bin/sh (por ejemplo,, ksh en OpenBSD).

El siguiente código debería funcionar en cualquier BSD:

$ echo {1..4}
{1..4}
$ seq 4
sh: seq: not found
$ for i in $(jot 4); do echo e$i; done
e1
e2
e3
e4
$
 1
Author: cnst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-23 04:54:55

Otra respuesta: Usar expansión de parámetros en parámetros vacíos:

# calls curl 4 times 
curl -s -w "\n" -X GET "http:{,,,}//www.google.com"

Probado en Centos 7 y macOS.

 1
Author: jcollum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-17 22:21:48

Resolví con este bucle, donde repeat es un entero que representa el número de los bucles

repeat=10
for n in $(seq $repeat); 
    do
        command1
        command2
    done
 1
Author: fvlgnn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-19 11:03:17

¿Qué tal la forma alternativa de for mencionada en (bashref)Construcciones de bucle?

 0
Author: SamB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-17 18:02:34

Los bucles For son probablemente la forma correcta de hacerlo, pero aquí hay una alternativa divertida:

echo -e {1..10}"\n" |xargs -n1 some_command

Si necesita el número de iteración como parámetro para su invocación, use:

echo -e {1..10}"\n" |xargs -I@ echo now I am running iteration @

Edit: Se comentó con razón que la solución dada anteriormente solo funcionaría sin problemas con simples ejecuciones de comandos (sin tuberías, etc.).). siempre puedes usar un sh -c para hacer cosas más complicadas, pero no vale la pena.

Otro método que uso normalmente es el siguiente función:

rep() { s=$1;shift;e=$1;shift; for x in `seq $s $e`; do c=${@//@/$x};sh -c "$c"; done;}

Ahora puedes llamarlo como:

rep 3 10 echo iteration @

Los dos primeros números dan el rango. El @ se traducirá al número de iteración. Ahora también puedes usar esto con tuberías:

rep 1 10 "ls R@/|wc -l"

Con darle el número de archivos en los directorios R1 .. R10.

 0
Author: stacksia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-16 13:51:31

El archivo de script

bash-3.2$ cat test.sh 
#!/bin/bash

echo "The argument is  arg: $1"

for ((n=0;n<$1;n++));
do
  echo "Hi"
done

Y la salida siguiente

bash-3.2$  ./test.sh 3
The argument is  arg: 3
Hi
Hi
Hi
bash-3.2$
 0
Author: upog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-10 16:45:10

Un poco ingenuo, pero esto es lo que generalmente recuerdo de la parte superior de mi cabeza:

for i in 1 2 3; do
  some commands
done

Muy similar a la respuesta de @joe-koberg. La suya es mejor, especialmente si necesita muchas repeticiones, solo que es más difícil para mí recordar otra sintaxis porque en los últimos años no estoy usando bash mucho. Quiero decir, no para escribir al menos.

 0
Author: akostadinov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 13:43:36