Wie führe ich einen Befehl mit der Bash-Shell mehrmals aus?


153

Gibt es eine Möglichkeit, einen Befehl (z. B. ps aux|grep someprocess) n- mal auszuführen ?

So etwas wie:

run -n 10  'ps aux|grep someprocess'

Ich möchte es interaktiv nutzen, bitte keine Skripte posten.

Update: Der Grund dafür ist, dass ich auf vielen Rechnern arbeite und nicht alle meine angepassten Skripte usw. in jede Box importieren möchte, um auf allen Rechnern die gleiche Funktionalität zu erhalten.


Antworten:


197

Ich glaube nicht, dass es dafür einen Befehl oder eine Shell gibt, da dies eine triviale Teilmenge dessen ist, wofür die Bourne-Shell- forSchleife entwickelt wurde, und die Implementierung eines solchen Befehls selbst daher recht einfach ist.

Für den Anfang können Sie eine Dummy- forSchleife verwenden:

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

Oder entsprechend dem Vorschlag von JimB, den eingebauten Bash-Code zum Generieren von Sequenzen zu verwenden:

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

Dies wird commandjedes Mal zehnmal wiederholt - es kann sich um eine Pipe oder eine Reihe von Befehlen handeln, die durch ;oder getrennt sind &&. Sie können die $iVariable verwenden, um zu ermitteln, in welcher Iteration Sie sich befinden.

Wenn Sie diesen Einzeiler für ein Skript halten und dies aus einem nicht näher definierten (aber möglicherweise gültigen) Grund unerwünscht ist, können Sie ihn als Befehl implementieren, möglicherweise in etwa so auf Ihrer .bashrc-Datei (ungetestet):

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

Verwendungszweck:

run 10 command

Beispiel:

run 5 echo 'Hello World!'

16
@ Mahatmanich, Eine Schleife ist kein Skript. Nichts hindert Sie daran, ... an einem interaktiven Terminal zu verwenden.
Zoredache

3
Nun, der Einzeiler oben ist die Art von Standardmethode und es ist ziemlich einfach. Warum ist es nicht gut für dich? Möglicherweise stellen Sie die falsche Frage? Was ist das Hauptziel Ihrer Skripte oder Ihrer Aktionen, die Sie mehrmals wiederholen möchten? Vielleicht gibt es eine bessere Lösung, wenn wir das Problem anders formulieren.
Patkos Csaba

6
@mahatmanich - for ist die eingebaute Bash zum Iterieren.
JimB

3
@Eduardo Ivanec - Zu Ihrer Information, bash hat eine eingebaute Reichweite wie seq: {1..10}
JimB

1
Es scheint, dass die eingebaute Klammersequenz keine Variablensubstitution unterstützt (siehe stackoverflow.com/a/3737773/713554 ). Die Funktion, die Sie angegeben haben, funktioniert einwandfrei, wenn sie in .bashrcif gestellt {1..$number} ist, wird jedoch gegen if ausgetauscht `seq $number`.
Leo

29

ps aux | grep someprocessSieht so aus, als ob Sie Änderungen eines Programms für eine bestimmte Zeit sehen möchten. Eduardo gab eine Antwort, die Ihre Frage genau beantwortete, aber es gibt eine Alternative watch:

watch 'ps aux | grep someprocess'

Beachten Sie, dass ich den Befehl in einfache Anführungszeichen gesetzt habe, um zu vermeiden, dass die Shell den Befehl als "run watch ps aux" interpretiert und das Ergebnis weiterleitet grep someprocess. Eine andere Möglichkeit, den vorherigen Befehl auszuführen, wäre:

watch ps aux \| grep someprocess

Standardmäßig werden watchalle zwei Sekunden Aktualisierungen durchgeführt, die mit der -nOption geändert werden können . Zum Beispiel, wenn Sie ein Intervall von 1 Sekunde haben wollen:

watch -n 1 'ps aux | grep someprocess'

21

Nur zum Spaß

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

Kann das bitte jemand erklären? Sieht sehr faszinierend aus.
Daniel Vartanov

4
; ist nur ein Befehlstrennzeichen. !! Wiederholen Sie den letzten Befehl in der Bash. Also starte 'pgrep ssh' und spiele es dann 6 mal ab.
Piotr Kukielka

Das ist zwar lehrreich, aber nicht sehr intuitiv. Einzeiler forscheint der beste Weg. Trotzdem danke für die Antwort.
erm3nda

1
Wird cmd ;!!in einer Zeile nicht einfach der vor der aktuellen Zeile eingegebene Befehl wiederholt ? Es müssten zwei separate historyEinträge sein.
Joel Purra

ersetzen ;mit &&, um beim ersten Ausfall anzuhalten.
User881300

16

Ähnlich wie bei vorherigen Antworten, erfordert jedoch keine for-Schleife:

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

Pipe-Ausgabe von seq an xargs ohne Argumente oder Optionen


2
Dies führt nur eine Ausführung aus echo "hello" 1 2 3 4 5 6 7 8 9 10. Sie müssen xargs mit -n 1für einen Prozess für jede Eingabe (Nummer) und mit -P 10für die parallele Ausführung (10 parallele Prozesse) ausführen. Am Ende mit seq 10 | xargs -n 1 -P 10 echo.
Alexander Klimetschek

16

Versuche dies:

yes ls | head -n5 | bash

Dies setzt voraus, dass der Befehl in einer Sub-Shell ausgeführt wird, was eine leichte Leistungsbeeinträchtigung darstellt. YMMV. Grundsätzlich erhalten Sie den Befehl "yes", um die Zeichenfolge "ls" N-mal zu wiederholen. während "head -n5" die Schleife bei 5 Wiederholungen beendete. Die letzte Pipe sendet den Befehl an die Shell Ihrer Wahl.

Übrigens haben cshähnliche Shells einen eingebauten repeatBefehl. Sie könnten das benutzen, um Ihren Befehl in einer bash-Sub-Shell auszuführen!


5

POSIX Weg

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

Das könnte natürlich zu einem Einzeiler gemacht werden:

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

und scheint der portabelste Weg zu sein, und daher ist es weniger wahrscheinlich, dass Sie Programme installieren.

Die folgenden sind weniger portabel:

  • Klammererweiterung {1..10}: bash-spezifisch und würde eine große Zeile erzeugen, wenn das Argument groß ist
  • seq: GNU
  • yes: GNU

Und wenn Sie die Portabilität satt haben, ziehen Sie GNU in Betracht parallel:

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

Das führt Befehle parallel aus und hat viele coole Optionen.

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


GNU Parallel ist sehr portabel. sh, zsh, kshund bashwerden auf den meisten Plattformen gut unterstützt. csh, tcsh, fishhat etwas Unterstützung. Mithilfe von können parallel --embedSie sogar ein Skript erstellen, das leicht auf ein anderes System verschoben werden kann, auf dem GNU Parallel nicht installiert ist.
Ole Tange

2

Eine Fischschalenimplementierung von @ eduardo-ivanecs runFunktion oben

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

0

Das wäre 'watch' - sollte Teil fast jedes Unix-Systems sein, das procps verwendet

Sie können Änderungen oder andere interessante Bewegungen in einem System sehen. Zum Beispiel,

watch "df -hP | grep /tmp" 

Setzen Sie einfach Ihre Befehle als Argument (siehe man watch)


Es gibt bereits eine Antwort mit Uhr ... siehe rechts unten ...
Mahatmanich

0

Unter macOS können Sie den repeatBefehl verwenden.

repeat 10 ps aux | grep someprocess
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.