So führen Sie Befehle wie in einer Warteschlange aus

35436
Svish

Ich muss viele Dateien in verschiedene Ordner kopieren. Ich kann alle meine Kopierbefehle zu einem Bash-Skript hinzufügen und dann ausführen, aber dann muss ich warten, bis der Vorgang abgeschlossen ist, wenn ich der "Warteschlange" weitere Befehle hinzufügen möchte.

Gibt es eine Möglichkeit, Befehle als Warteschlange auszuführen und der Warteschlange während der Ausführung weitere Befehle hinzuzufügen?

Anders gesagt, möchte ich eine lange laufende Aufgabe beginnen. Während das läuft, möchte ich ein anderes starten, das erst startet, wenn das erste fertig ist. Und dann noch einen nach dem letzten und so weiter. Ist das irgendwie möglich?

37
Darf ich vorschlagen, dass Sie eine Antwort akzeptieren, die Ihr Problem löst? Es scheint, dass es ein paar von ihnen gibt, die für Sie arbeiten würden. holmb vor 11 Jahren 3
Ja können Sie, und ich wollte. Das Problem ist, dass ich das gefragt habe, als ich in einer Firma gearbeitet habe, die Macs verwendet. Ich arbeite nicht mehr dort und habe selbst keine Macs, daher kann ich keine davon testen. Fühlen Sie sich nicht wohl damit, eine als Antwort zu kennzeichnen, wenn ich nicht testen kann, ob es tatsächlich funktioniert. Deshalb habe ich gehofft, dass die Leute die Antworten wählen, die sie für sie gut finden, so dass die "Antwort" auf diese Weise entstehen kann stattdessen. Svish vor 11 Jahren 2

8 Antworten auf die Frage

23
Gilles

Das atDienstprogramm, das am besten für die Ausführung von Befehlen zu einem bestimmten Zeitpunkt bekannt ist, verfügt auch über eine Warteschlangenfunktion und kann aufgefordert werden, Befehle jetzt auszuführen. Es liest den Befehl zum Ausführen von der Standardeingabe.

echo 'command1 --option arg1 arg2' | at -q myqueue now echo 'command2 ...' | at -q myqueue now 

Der batchBefehl ist äquivalent zu at -q b -m now( -mbedeutet, dass die Befehlsausgabe, falls vorhanden, an Sie gesendet wird, wie es bei cron der Fall ist). Nicht alle Unix-Varianten unterstützen Warteschlangennamen ( -q myqueue). Sie können auf eine einzelne aufgerufene Warteschlange beschränkt sein b. Linux atist auf Ein-Buchstaben-Warteschlangennamen beschränkt.

Zumindest unter Linux scheint dies nicht zu warten, bis der vorherige Befehl beendet ist. wds vor 9 Jahren 2
@wds Arbeitet für mich unter Debian Wheezy. Wo und wie ist es für dich kaputt gegangen? Beachten Sie, dass at nur wartet, bis der Befehl beendet ist. Wenn der Befehl Unterprozesse startet, die das übergeordnete Element überleben, wartet at nicht auf die Unterprozesse. Gilles vor 9 Jahren 0
Ich habe es mit CentOS 6 versucht. Ich habe es mit einem einfachen "sleep x" getestet. Ich bin nicht sicher, was bei at ausgeführt wird, aber ich gehe davon aus, dass eine Subshell gestartet wird und diese Subshell auf das Ergebnis warten soll (ein Sleep-Call kehrt nicht sofort zurück). wds vor 9 Jahren 0
Neben den Namen der Warteschlangen erscheint "jetzt" auch nicht als Standard: bash on ubuntu beschwert sich darüber ... winwaed vor 8 Jahren 0
@winwaed Oh, es ist "jetzt", nicht "-t jetzt", sorry. Ich hatte nicht bemerkt, dass ich im Beispielcode falsch war. Gilles vor 8 Jahren 0
@ Gilles: Schnelle Antwort auf einen alten Thread. Am Ende habe ich einen Python-Workaround für das implementiert, was ich wollte, aber ich kann darauf zurückkommen, wenn es beim Testen zu einem Schmerz wird! (Bash aufrufen Python aufrufen Bash könnte sauberer sein ...) winwaed vor 8 Jahren 0
Es scheint jedoch nicht die Reihenfolge der Warteschlange zu respektieren ... Michael vor 6 Jahren 0
21
Vortico

Hängen Sie &an das Ende Ihres Befehls, um ihn in den Hintergrund zu senden, und dann waitdarauf, bevor Sie den nächsten ausführen. Zum Beispiel:

$ command1 & $ wait; command2 & $ wait; command3 & $ ... 
Yay! Diese Syntax ist großartig, wenn Sie etwas losgelassen haben und sich Stackoverflow ansehen, um nach etwas zu suchen Erik Aronesty vor 12 Jahren 2
Wenn Sie Ihre Meinung zu einem dieser Befehle in der Zwischenzeit ändern, was kann getan werden, um das Warten abzubrechen? Es scheint für alle meine Abschüsse undurchdringlich. Ken Williams vor 11 Jahren 2
Sie töten einfach den Befehl. Das "Warten" stoppt einfach den Job, bis die vorherigen beendet sind. Gert Sønderby vor 9 Jahren 1
Funktioniert das mit "nohup"? Michael vor 6 Jahren 0
11
Jordan

Die Lösungen von Brad und Mankoff sind gute Vorschläge. Eine andere Kombination, die einer Kombination aus beiden ähnelt, wäre die Verwendung von GNU Screen zur Implementierung Ihrer Warteschlange. Dies hat den Vorteil, dass es im Hintergrund ausgeführt werden kann, Sie können es jederzeit überprüfen und fügt neue Befehle in die Warteschlange ein, die einfach in den Puffer eingefügt werden, der nach dem Beenden des vorherigen Befehls ausgeführt werden soll.

Erster Lauf:

$ screen -d -m -S queue 

( Übrigens ist jetzt ein guter Zeitpunkt, um mit einigen fantastischen. screenrc-Dateien zu spielen. )

Daraufhin wird eine Hintergrundbildschirmsitzung für Ihre benannte Warteschlange angezeigt.

Jetzt können Sie beliebig viele Befehle in die Warteschlange stellen:

screen -S queue -X stuff "echo first; sleep 4; echo second^M" 

Ich mache oben mehrere Befehle, nur zum Testen. Ihr Anwendungsfall würde wahrscheinlich eher wie folgt aussehen:

screen -S queue -X stuff "echo first^M" screen -S queue -X stuff "echo second^M" 

Beachten Sie, dass das "^ M" in meiner Zeile oben eine Möglichkeit ist, eine eingebettete Newline zu erhalten, die später interpretiert wird, nachdem screen sie in Ihre vorhandene Bash-Shell eingefügt hat. Verwenden Sie "CTL-V", um diese Sequenz zu erhalten.

Es wäre ziemlich einfach, einige einfache Shell-Skripte zu erstellen, um dies zu automatisieren und Befehle in die Warteschlange zu stellen. Immer dann, wenn Sie den Status Ihrer Hintergrundwarteschlange überprüfen möchten, verbinden Sie sich erneut über:

screen -S queue -r 

Technisch müssen Sie nicht einmal Ihre Bildschirmsitzung benennen, und es wird gut funktionieren, aber wenn Sie erst einmal daran interessiert sind, werden Sie sowieso die ganze Zeit laufen lassen wollen. ;-)

Wenn Sie dies tun, können Sie natürlich auch eines der aktuellen Fenster "Warteschlange" nennen und Folgendes verwenden:

screen -S queue -p queue -X stuff "command" 
Es scheint so, als würde der Befehl in der laufenden Bildschirmsitzung im Wesentlichen nur "eingegeben". Wenn also die Shell nach Abschluss des ersten Befehls wieder die Kontrolle übernimmt, wird dieser Befehl gestartet. Mit anderen Worten, es ist gleichbedeutend mit der Lösung von @mankoff, verwendet jedoch ein ausgefalleneres Werkzeug für die Eingabe. Ken Williams vor 11 Jahren 0
Ziemlich viel - der Hauptunterschied besteht darin, dass die Bildschirmlösung eine bessere Automatisierung unterstützt. Sie können einige Sachen von Hand machen, andere Dinge mit Skripten, alle mit einer einfachen Schnittstelle. Jordan vor 11 Jahren 0
7
holmb

Es gibt ein Dienstprogramm, das ich mit großem Erfolg für genau den Anwendungsfall verwendet habe, den Sie beschreiben. Vor kurzem habe ich meinen primären Laptop auf neue Hardware umgestellt, bei der einige Dateien auf einen NAS und der Rest auf den neuen Computer verschoben wurden.

So habe ich es gemacht.

  1. Richten Sie alle an einer Netzwerkverbindung beteiligten Maschinen so ein, dass sie sich gegenseitig erreichen können.

  2. Installieren Sie auf dem Computer, von dem aus Sie Dateien verschieben (im Folgenden als Quellcomputer bezeichnet), rsync mit apt-get install rsyncund den geheimen Soße- Taskspooler (Website http://vicerveza.homeunix.net/~viric/soft/ts/ ). Wenn Sie sich unter Debian befinden, wird der Paketname für tsist task-spoolerund die ausführbare Datei in umbenannt, tspum einen Namenskonflikt mit der tsausführbaren Datei aus dem moreutilsPaket zu vermeiden . Das Debian-Paket, das von der Website aus verlinkt wird, kann mit Ubuntu dpkg -i task-spooler_0.7.3-1_amd64.deboder ähnlichem perfekt installiert werden .

  3. Stellen Sie außerdem sicher, dass auf allen Computern SSH installiert ist apt-get install openssh-server. Auf der Quellmaschine müssen Sie SSH einrichten, um die kennwortlose Anmeldung an den Zielmaschinen zu ermöglichen. Die am häufigsten verwendete Methode ist die Public-Key-Authentifizierung mit ssh-agent(siehe https://www.google.se/search?q=ssh+public+key+authentication ), aber ich verwende manchmal eine einfachere Methode, die einfach funktioniert auch bei der Passwortauthentifizierung. Fügen Sie der SSH-Client-Konfiguration Folgendes hinzu (entweder ~/.ssh/configoder /etc/ssh/ssh_config):

    Host * ControlMaster auto ControlPath ~/.ssh/master-%r@%h:%p 

    Öffnen Sie dann ein Terminal auf dem Quellcomputer, melden Sie sich mit an ssh target1, authentifizieren Sie sich wie gewohnt und lassen Sie dieses Terminal geöffnet. Beachten Sie, dass eine Socket-Datei benannt ~/.ssh/master-user@target1:22ist. Dies ist die Datei, die eine authentifizierte Mastersitzung geöffnet hält und nachfolgende kennwortlose Verbindungen zulässt user(sofern die Verbindung denselben Ziel-Hostnamen und -Port verwendet).

    An diesem Punkt müssen Sie sicherstellen, dass Sie sich anmelden können, ohne zur Authentifizierung auf den Zielcomputern aufgefordert zu werden.

  4. Führen Sie nun ts rsync -ave ssh bigfile user@target1:eine einzelne Datei oder ts rsync -ave ssh bigdir user@target1:ein Verzeichnis aus. Bei rsync ist es wichtig, dass im Verzeichnis kein nachstehender Schrägstrich eingefügt wird (im bigdirVergleich zu bigdir/), da rsync davon ausgeht, dass Sie mit den bigdir/*meisten anderen Tools gleichwertig waren .

    Der Task-Spooler gibt die Aufforderung zurück und lässt Sie viele dieser Befehle nacheinander in die Warteschlange stellen. Überprüfen Sie die Laufwarteschlange tsohne Argumente.

Der Task-Spooler verfügt über viele Funktionen, z. B. das Neuanordnen der Laufwarteschlange, das Ausführen eines bestimmten Jobs nur, wenn ein anderer Job erfolgreich ausgeführt wurde ts -h. Manchmal überprüfe ich die Befehlsausgabe, während sie mit läuft ts -c.

Es gibt andere Methoden, dies zu tun, aber für Ihren Anwendungsfall enthalten sie alle den Task-Spooler. Ich wähle rsync über SSH, um Dateizeitstempel beizubehalten, die beim Kopieren über SMB nicht vorhanden wären.

Vielen Dank für Ihre Antwort, die ich nicht über 'ts' kannte. Sie scheinen sehr mächtig und einfach zu verwenden. Sie werden einfach [github] (https://github.com/xenogenesi/task-spooler.git) autotoolisiert und debianisiert. Alex vor 10 Jahren 0
@Alex Ich habe mir Ihre Gabel angesehen und war besonders daran interessiert, was mit dem Autotooling und dem Debianisieren der Originalquelle unternommen wurde. Wenn Sie sich Ihre Commits ansehen, war es nicht einfach als Unterschied zur Originalquelle verfügbar. Würdest du gerne zwingen, neue Commits voranzutreiben, die in Schritt 1. Originalquelle importieren und 2. mit deinen Ergänzungen festlegen? Es hilft jemandem, der Ihre Quelle durchsucht, um (leichter) Ihre Ergänzungen der Originalquelle anzuvertrauen. Dies ist eines der wenigen Pakete, die ich nicht von einem PPA oder ähnlichem installiere. Es wäre also schön, es selbst mit Ihrer Gabel zu bauen. holmb vor 10 Jahren 0
Sie wissen, ich muss meine Brille wechseln, ich habe den Teil Ihrer Antwort zu dem vorhandenen Task-Spooler verloren :-) ... jedenfalls ist das in Ihrem Kommentar ein sehr guter Vorschlag, ich werde es sehr bald tun. Alex vor 10 Jahren 0
das Repository mit progressiven Commits erstellt, gelöscht und neu erstellt, nur ein paar Fehler (sollten vor dem Push weitere lokale Commits verstoffwechseln) Alex vor 10 Jahren 0
4
Ken Williams

Ich brauche auch ziemlich oft solche Sachen. Ich habe ein kleines Hilfsprogramm geschrieben after, das einen Befehl ausführt, sobald ein anderer Prozess abgeschlossen ist. Es sieht aus wie das:

#!/usr/bin/perl  my $pid = shift; die "Usage: $0 <pid> <command...>" unless $pid =~ /^\d+$/ && @ARGV;  print STDERR "Queueing process $$ after process $pid\n"; sleep 1 while -e "/proc/$pid"; exec @ARGV; 

Sie führen es dann so aus:

% command1 arg1 arg2 ... # creates pid=2853 % after 2853 command2 arg1 arg2 ... # creates pid=9564 % after 9564 command3 arg1 arg2 ... 

Der große Vorteil gegenüber einigen anderen Ansätzen besteht darin, dass der erste Job nicht auf besondere Weise ausgeführt werden muss. Sie können jeden Prozess mit Ihrem neuen Job verfolgen.

Nettes Skript @ken. Ich würde jedoch empfehlen, den Task Spooler auszuprobieren, da Sie dies anscheinend gelegentlich benötigen. Sehen Sie meine Antwort. holmb vor 11 Jahren 0
Looks neat, thanks. The one thing missing from TS seems to be the ability to follow jobs that weren't started under TS. Though I guess you could start a new TS job whose purpose is just to wait for an existing process to finish. Ken Williams vor 11 Jahren 0
Tatsächlich. Das ist ein nützlicher Aspekt Ihrer Lösung. holmb vor 11 Jahren 0
1

Sie können der Kommandozeile der Shell, die bereits einen Befehl ausführt, einfach Befehle hinzufügen.

Entweder vorsichtig eingeben oder an anderer Stelle eingeben, überprüfen und ausschneiden. Auch wenn der aktuelle Befehl Zeilen für die Ausgabe spuckt, können Sie immer noch etwas Neues eingeben und die Eingabetaste drücken. Der Befehl wird ausgeführt, wenn alle Befehle ausgeführt oder vor dem Abschluss eingegeben wurden.

Beispiel folgt. Sie können das Ganze ausschneiden und einfügen oder die folgenden Befehle eingeben, während der 1. Befehl ausgeführt wird (wenn Sie wirklich sehr schnell eingeben) oder wahrscheinlicher, während der 2. Befehl läuft.

echo "foo" sleep 10; echo "bar" sleep 3 echo "baz" 
1
naftuli

Befehl1 && Befehl2

  • "&&" bedeutet, dass command2 erst ausgeführt wird, nachdem command1 mit dem Rückkehrcode 0 beendet wurde
  • Anmerkung: a || bedeutet, dass command2 erst ausgeführt wird, nachdem command1 mit einem Rückgabecode abweichend von 0 beendet wurde
0
Brad Clawsie

Der hackste Weg, den ich mir vorstellen kann, ist, den Warteschlangenstatus mit einfachen Sperrdateien in / tmp aufrechtzuerhalten. Wenn file1.sh seine cp-Befehle ausführt, wird eine Sperrdatei (oder einen Hardlink) in / tmp gespeichert. Wenn es fertig ist, löschen Sie die Datei. Jedes andere Skript muss in / tmp nach Sperrdateien mit dem von Ihnen gewählten Namensschema suchen. Natürlich unterliegt dies allen möglichen Fehlern, aber es ist trivial einzurichten und ist vollständig innerhalb von bash möglich.

In der Praxis schwierig zu verwenden, da für jeden Job, den Sie ausführen möchten, geändert werden muss, um die Sperrdateien beizubehalten, und dass er wissen muss (oder als Parameter akzeptiert), * welche * Sperrdateien verwendet werden sollen. Wann immer möglich, ist es am besten, die Warteschlange außerhalb des Jobs zu haben. Ken Williams vor 11 Jahren 0