Come eseguire un comando più volte, usando la shell bash?


153

C'è un modo per eseguire un comando (ad esempio ps aux|grep someprocess) per n volte?

Qualcosa di simile a:

run -n 10  'ps aux|grep someprocess'

Voglio usarlo in modo interattivo, per favore non pubblicare script.

Aggiornamento: il motivo per cui lo sto chiedendo è che lavoro su molte macchine e non voglio importare tutti i miei script adattati ecc. In ogni scatola per ottenere la stessa funzionalità su ogni macchina.


Risposte:


197

Non credo che esista un comando o una shell incorporata per questo, in quanto è un sottoinsieme banale forper cui è progettato il loop di shell Bourne e l'implementazione di un comando come questo da soli è quindi abbastanza semplice.

Per cominciare puoi usare un foranello fittizio :

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

O equivalentemente secondo il suggerimento di JimB, usando il Bash incorporato per generare sequenze:

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

Esegue ripetutamente l'esecuzione dieci volte command: può essere una pipe o una serie di comandi separati da ;o &&. Puoi usare la $ivariabile per sapere in quale iterazione ti trovi.

Se consideri questo one-liner uno script e quindi per qualche motivo non specificato (ma forse valido) indesiderabile puoi implementarlo come comando, forse qualcosa del genere sul tuo .bashrc (non testato):

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

Uso:

run 10 command

Esempio:

run 5 echo 'Hello World!'

16
@mahatmanich, Un ciclo non è uno script. Non c'è nulla che ti impedisca di utilizzare per ... in un terminale interattivo.
Zoredache,

3
Bene, il one-liner sopra è il tipo di modo standard per farlo ed è abbastanza semplice. Perché non ti fa bene? Forse stai facendo la domanda sbagliata? Qual è l'obiettivo principale dei tuoi script o delle tue azioni che desideri ripetere più volte? Forse c'è una soluzione migliore se mettiamo il problema in modo diverso.
Patkos Csaba,

6
@mahatmanich - for è il bash integrato per iterare.
JimB,

3
@Eduardo Ivanec - FYI, bash ha un range integrato come seq: {1..10}
JimB

1
Sembra che la sequenza di parentesi incorporata non supporti la sostituzione variabile (consultare stackoverflow.com/a/3737773/713554 ). La funzione che hai dato funziona perfettamente se inserita .bashrcse {1..$number} è scambiata per `seq $number`però.
Leone

29

ps aux | grep someprocesssembra che tu voglia guardare i cambiamenti di un programma per un tempo fisso. Eduardo ha dato una risposta che risponde esattamente alla tua domanda ma esiste un'alternativa watch:

watch 'ps aux | grep someprocess'

Si noti che ho inserito il comando tra virgolette singole per evitare che la shell interpreti il ​​comando come "run watch ps aux" e instrada il risultato grep someprocess. Un altro modo per eseguire il comando precedente sarebbe:

watch ps aux \| grep someprocess

Per impostazione predefinita, si watchaggiorna ogni due secondi, che può essere modificato utilizzando l' -nopzione. Ad esempio, se si desidera avere un intervallo di 1 secondo:

watch -n 1 'ps aux | grep someprocess'

21

Solo per divertimento

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

Qualcuno può spiegare questo per favore? Sembra molto intrigante.
Daniel Vartanov,

4
; è solo un comando di separazione. !! riproduce l'ultimo comando in bash. Quindi esegui 'pgrep ssh' e poi riproducilo 6 volte.
Piotr Kukielka,

Mentre questo è istruttivo non è molto intuitivo. One-liner forsembra il modo migliore. Comunque grazie per la risposta.
erm3nda,

1
Will non cmd ;!!su una sola riga è sufficiente ripetere il comando inserito prima che la linea attuale? Dovrebbero essere due historyvoci separate .
Joel Purra,

sostituire ;con &&per interrompere al primo errore.
user881300

16

simile alle risposte precedenti, ma non richiede il ciclo for:

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

pipe pipe di seq in xargs senza argomenti o opzioni


2
Questo farà solo una esecuzione echo "hello" 1 2 3 4 5 6 7 8 9 10. È necessario eseguire xargs con -n 1per un processo per ciascun input (numero) e con -P 10per l'esecuzione parallela (10 processi paralleli). Finendo con seq 10 | xargs -n 1 -P 10 echo.
Alexander Klimetschek,

16

Prova questo:

yes ls | head -n5 | bash

Ciò richiede che il comando sia eseguito in una sotto-shell, una leggera penalità prestazionale. YMMV. Fondamentalmente, si ottiene il comando "yes" per ripetere la stringa "ls" N volte; mentre "head -n5" ha terminato il loop con 5 ripetizioni. La pipe finale invia il comando alla shell di tua scelta.

Le cshshell casuali hanno un repeatcomando integrato . Potresti usarlo per eseguire il tuo comando in una sub-shell bash!


5

Modo 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

che ovviamente potrebbe essere trasformato in una fodera:

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

e sembra essere il modo più portatile, e quindi meno probabilità di farti installare programmi.

I seguenti sono meno portatili:

  • espansione parentesi {1..10}: specifica bash, e genererebbe una linea enorme se l'argomento è grande
  • seq: GNU
  • yes: GNU

E se ti stanchi della portabilità, considera GNU parallel:

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

che esegue i comandi in parallelo e ha molte opzioni interessanti.

Vedi anche: https://stackoverflow.com/questions/169511/how-do-i-iterate-over-a-range-of-numbers-defined-by-variables-in-bash


GNU Parallel è progettato per essere molto portatile. sh, zsh, kshe bashsono tutti ben supportati sulla maggior parte delle piattaforme. csh, tcsh, fishha un po 'di supporto. Usando parallel --embedpuoi persino creare uno script che può essere facilmente spostato su un altro sistema su cui non è installato GNU Parallel.
Ole Tange,

2

Un'implementazione di shell di pesce della runfunzione di @ eduardo-ivanec sopra

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

0

Sarebbe 'guardare' - dovrebbe far parte di quasi tutti i sistemi unix che usano procps

Puoi vedere cambiamenti fs o movimenti interessanti in un sistema. Per esempio,

watch "df -hP | grep /tmp" 

Inserisci i tuoi comandi come argomento (vedi man watch)


C'è già una risposta con l'orologio ... vedi sotto ...
mahatmanich,

0

Su macOS puoi usare il repeatcomando.

repeat 10 ps aux | grep someprocess
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.