¿Cómo ejecutar un comando varias veces, usando bash shell?


153

¿Hay alguna forma de ejecutar un comando (por ejemplo ps aux|grep someprocess) n veces?

Algo como:

run -n 10  'ps aux|grep someprocess'

Quiero usarlo de forma interactiva, no publique scripts.

Actualización: La razón por la que pregunto esto es porque trabajo en muchas máquinas y no quiero importar todos mis scripts adaptados, etc. en cada cuadro para obtener la misma funcionalidad en cada máquina.


Respuestas:


197

No creo que exista un comando o shell incorporado para esto, ya que es un subconjunto trivial de para qué forestá diseñado el bucle de shell Bourne y, por lo tanto, implementar un comando como este es bastante simple.

Para empezar, puede usar un forbucle ficticio :

for i in `seq 10`; do command; done

O, de manera equivalente, según la sugerencia de JimB, utilizando el Bash incorporado para generar secuencias:

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

Esto se repite diez veces ejecutándose commandcada vez: puede ser una tubería o una serie de comandos separados por ;o &&. Puedes usar la $ivariable para saber en qué iteración estás.

Si considera que este one-liner es un script y, por alguna razón no especificada (pero quizás válida) indeseable, puede implementarlo como un comando, tal vez algo como esto en su .bashrc (no probado):

#function run
run() {
    number=$1
    shift
    for i in `seq $number`; do
      $@
    done
}

Uso:

run 10 command

Ejemplo:

run 5 echo 'Hello World!'

16
@mahatmanich, Un bucle no es un script. No hay nada que le impida usar para ... en una terminal interactiva.
Zoredache

3
Bueno, la línea de arriba es el tipo de forma estándar de hacerlo y es bastante simple. ¿Por qué no es bueno para ti? Tal vez estás haciendo la pregunta equivocada? ¿Cuál es el objetivo principal de sus guiones o sus acciones que desea repetir varias veces? Quizás haya una mejor solución si planteamos el problema de otra manera.
Patkos Csaba

66
@mahatmanich: for es el bash integrado para iterar.
JimB

3
@Eduardo Ivanec - Para su información, bash tiene un rango incorporado como seq: {1..10}
JimB

1
Parece que la secuencia de paréntesis incorporada no admite la sustitución de variables (consulte stackoverflow.com/a/3737773/713554 ). Sin embargo, la función que proporcionó funciona perfectamente cuando se coloca .bashrcsi {1..$number} se intercambia `seq $number`.
Leo

29

ps aux | grep someprocessParece que desea ver los cambios de un programa durante un tiempo fijo. Eduardo dio una respuesta que responde a su pregunta exactamente pero hay una alternativa watch:

watch 'ps aux | grep someprocess'

Tenga en cuenta que he puesto el comando entre comillas simples para evitar que el shell interprete el comando como "ejecutar watch ps aux" y canalizar el resultado grep someprocess. Otra forma de hacer el comando anterior sería:

watch ps aux \| grep someprocess

Por defecto, se watchactualiza cada dos segundos, eso se puede cambiar usando la -nopción. Por ejemplo, si desea tener un intervalo de 1 segundo:

watch -n 1 'ps aux | grep someprocess'

21

Solo por diversión

pgrep ssh ;!!;!!;!!;!!;!!;!!

¿Puede alguien explicar esto, por favor? Se ve muy intrigante.
Daniel Vartanov

44
; es solo un separador de comandos. !! reproducir el último comando en bash. Entonces ejecute 'pgrep ssh' y luego repítalo 6 veces.
Piotr Kukielka

Si bien eso es instructivo, no es muy intuitivo. One-liner forparece la mejor manera. De todos modos, gracias por la respuesta.
erm3nda

1
¿No cmd ;!!se repetirá en una línea el comando introducido antes de la línea actual? Tendrían que ser dos historyentradas separadas .
Joel Purra

reemplace ;con &&para detenerse en la primera falla.
user881300

16

similar a las respuestas anteriores, pero no requiere el ciclo for:

seq 10 | xargs -I -- echo "hello"

salida de tubería de seq a xargs sin argumentos u opciones


2
Esto solo hará una ejecución echo "hello" 1 2 3 4 5 6 7 8 9 10. Debe ejecutar xargs con -n 1un proceso para cada entrada (número) y con -P 10ejecución paralela (10 procesos paralelos). Terminando con seq 10 | xargs -n 1 -P 10 echo.
Alexander Klimetschek

16

Prueba esto:

yes ls | head -n5 | bash

Esto requiere que el comando se ejecute en un sub-shell, una leve penalización de rendimiento. YMMV. Básicamente, obtienes el comando "yes" para repetir la cadena "ls" N veces; mientras que "head -n5" finalizó el ciclo en 5 repeticiones. La tubería final envía el comando al shell de su elección.

Por cierto, los cshproyectiles tienen un repeatcomando incorporado . ¡Podrías usar eso para ejecutar tu comando en un bash shell!


5

Manera POSIX

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04_01

x=10
while [ $x -gt 0 ]; do
    command
    x=$(($x-1))
done

que por supuesto podría convertirse en una línea:

x=10; while [ $x -gt 0 ]; do command; x=$(($x-1)); done

y parece ser la forma más portátil y, por lo tanto, es menos probable que haga que instale programas.

Los siguientes son menos portátiles:

  • expansión de {1..10}llaves: bash específico, y generaría una línea enorme si el argumento es grande
  • seq: GNU
  • yes: GNU

Y si te cansas de la portabilidad, considera GNU parallel:

sudo apt-get install parallel
seq 100 | parallel echo {}

que ejecuta comandos en paralelo y tiene muchas opciones interesantes.

Ver también: https://stackoverflow.com/questions/169511/how-do-i-iterate-over-a-range-of-numbers-defined-by-variables-in-bash


GNU Parallel está diseñado para ser muy portátil. sh, zsh, ksh, y bashtodos están bien soportados en la mayoría de las plataformas. csh, tcsh, fishTiene algo de apoyo. Al parallel --embedusarlo, incluso puede crear un script que se pueda mover fácilmente a otro sistema que no tenga GNU Parallel instalado.
Ole Tange

2

Una implementación de concha de pescado de la runfunción de @ eduardo-ivanec anterior

function run
  set number $argv[1]
  for i in (seq $number)
    eval $argv[2..-1]
  end
end

0

Eso sería 'ver', debería ser parte de casi todos los sistemas Unix que usan procps

Puede ver cambios fs o movimientos interesantes en un sistema. Por ejemplo,

watch "df -hP | grep /tmp" 

Simplemente ponga sus comandos como argumento (ver man watch)


Ya hay una respuesta con el reloj ... ver a continuación ...
mahatmanich

0

En macOS puedes usar el repeatcomando.

repeat 10 ps aux | grep someprocess
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.