bash-Shell:starten Sie mehrere verkettete Befehle im hintergrund
-
03-07-2019 - |
Frage
Ich versuche, einige Befehle in paralel, im hintergrund, mit bash.Hier ist, was ich versuche zu tun:
forloop {
//this part is actually written in perl
//call command sequence
print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}
Der Teil zwischen backticks (`) erzeugt eine neue shell und führt die Befehle nacheinander aus.Das Ding ist, die Kontrolle an das ursprüngliche Programm zurück, nur nachdem der Letzte Befehl ausgeführt wurde.Ich möchte Ausführung der gesamten Anweisung im hintergrund (ich bin nicht zu erwarten, dass jede Ausgabe/Rückgabe-Werte) und ich möchte, dass die Schleife weiter ausgeführt.
Das aufrufende Programm (die eine, die hat die Schleife) würde nicht enden, bis alle hervorgebracht Muscheln fertig stellen.
Ich konnte verwenden Sie threads in perl, um zu laichen verschiedene threads, die call-verschiedene Muscheln, aber es scheint ein overkill...
Kann ich eine shell, geben Sie ihm eine Reihe von Befehlen und sagen, es zu gehen, um die hintergrund?
Lösung
Ich habe nicht dieses aber, wie etwa
getestetprint `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;
Die Klammern bedeuten in einer Subshell auszuführen, aber das sollte nicht weh tun.
Andere Tipps
Dank Hugh, dass es tat:
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
adrianp@frost:~$ stopped
[1]+ Done ( echo "started"; sleep 15; echo "stopped" )
adrianp@frost:~$
Die anderen Ideen nicht funktionieren, weil sie jeden Befehl im Hintergrund zu starten, und nicht die Befehlsfolge (was in meinem Fall wichtig ist!).
Vielen Dank noch einmal!
Eine andere Möglichkeit ist die folgende Syntax zu verwenden:
{ command1; command2; command3; } &
wait
Beachten Sie, dass die &
am Ende der Befehlsgruppe geht, nicht nach jedem Befehl. Das Semikolon nach dem letzten Befehl ist notwendig, da der Raum nach der ersten Klammer und vor der endgültigen Klammer ist. Die wait
am Ende wird sichergestellt, dass der übergeordnete Prozess nicht vor der erzeugte Kindprozess endet getötet wird (der Befehl Gruppe).
Sie können auch fancy stuff tun wie Umleiten stderr
und stdout
:
{ command1; command2; command3; } 2>&2 1>&1 &
Ihr Beispiel würde wie folgt aussehen:
forloop() {
{ touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end
for command in $commands
do
"$command" &
done
wait
Die Et-Zeichen am Ende des Befehls laufen es im Hintergrund, und die wait
warten, bis die Hintergrundaufgabe abgeschlossen ist.
GavinCattell bekam in der Nähe (für bash , IMO), sondern als Mad_Ady darauf hingewiesen, wäre es nicht die „sperren“ Dateien. Dies sollte:
Wenn es andere Aufträge anstehen, die warten wird für diejenigen warten, auch. Wenn Sie warten müssen, nur die Kopien, können Sie diese PIDs ansammeln und für nur diejenigen warten. Wenn nicht, könnten Sie die drei Zeilen mit „PIDs“ löschen, aber es ist allgemeiner.
Darüber hinaus habe ich die Überprüfung der Kopie insgesamt zu vermeiden:
pids=
for file in bigfile*
do
# Skip if file is not newer...
targ=/destination/$(basename "${file}")
[ "$targ" -nt "$file" ] && continue
# Use a lock file: ".fileN.lock" for each "bigfileN"
lock=".${file##*/big}.lock"
( touch $lock; cp "$file" "$targ"; rm $lock ) &
pids="$pids $!"
done
wait $pids
Im übrigen sieht es aus wie Sie neue Dateien auf einen FTP-Repository sind kopieren (oder ähnliches). Wenn ja, Sie könnte sollten Sie eine Kopie / umbenennen Strategie anstelle der Lock-Dateien (aber das ist ein anderes Thema).
Die Anlage in bash, die Sie suchen Compound Commands
genannt wird. Siehe Manpage für weitere Informationen:
Compound-Befehle Eine Verbindung Befehl ist einer der folgenden:
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list. { list; } list is simply executed in the current shell environment. list must be terminated with a newline or semicolon. This is known as a group command. The return status is the exit status of list. Note that unlike the metacharac‐ ters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharac‐ ter.
Es gibt andere, aber diese sind wahrscheinlich die zwei häufigsten Arten. Die erste, die Pars, wird in einer Unterschale, während der zweiten, die geschweiften Klammern wird eine Liste von Befehlen, die in Reihe in der aktuellen Shell eine Liste des Befehls in Serie ausgeführt werden.
parens
% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013
geschweiften Klammern
% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013
Führen Sie den Befehl durch ein an Job mit:
# date
# jue sep 13 12:43:21 CEST 2012
# at 12:45
warning: commands will be executed using /bin/sh
at> command1
at> command2
at> ...
at> CTRL-d
at> <EOT>
job 20 at Thu Sep 13 12:45:00 2012
Das Ergebnis wird auf Ihr Konto per E-Mail gesendet werden.
stieß ich auf diesen Thread hier und beschlossen, einen Code-Schnipsel zusammen zu stellen gekettet Aussagen als Hintergrundjobs zu laichen. Getestet habe ich diese auf BASH für Linux, KSH für IBM AIX und Busybox ASH für Android, so dass ich denke, es ist sicher zu sagen, es funktioniert auf jeder Bourne-artig Shell.
processes=0;
for X in `seq 0 10`; do
let processes+=1;
{ { echo Job $processes; sleep 3; echo End of job $processes; } & };
if [[ $processes -eq 5 ]]; then
wait;
processes=0;
fi;
done;
Dieser Code führt eine Reihe von Hintergrundjobs bis zu einer gewissen Grenze der gleichzeitigen Arbeitsplätze. Sie können damit zum Beispiel eine Menge von gzip-Dateien mit xz
erneut zu komprimieren, ohne einem riesigen Haufen xz
Prozesse isst Ihren gesamten Speicher und den Computer erbrechen machen: in diesem Fall Sie *
als die for
Liste verwenden und die Charge Job würde gzip -cd "$X" | xz -9c > "${X%.gz}.xz"
werden.
die Befehle in einer Subshell ausgeführt werden:
(command1 ; command2 ; command3) &
Versuchen Sie Befehle in geschweiften Klammern mit & s zu setzen, wie folgt aus:
{command1 & ; command2 & ; command3 & ; }
Dies schafft nicht eine Unterschale, sondern führt die Gruppe von Befehlen in den Hintergrund.
HTH
Ich weiß nicht, warum niemand mit der richtigen Lösung antwortete:
my @children;
for (...) {
...
my $child = fork;
exec "touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;" if $child == 0;
push @children, $child;
}
# and if you want to wait for them to finish,
waitpid($_) for @children;
Dies bewirkt, dass Perl Kinder zum Laichen jeden Befehl auszuführen, und ermöglicht es Ihnen, für alle Kinder, bevor Sie fortfahren zu vervollständigen, zu warten.
Durch die Art und Weise,
print `some command`
und
system "some command"
Ausgabe auf stdout, die gleichen Inhalte, aber der erste hat einen höheren Aufwand, als Perl alle „some command
“ 's Ausgabe
in einem Forking for-Schleife:
for i in x; do ((a; b; c;)&); done
Beispiel:
for i in 500 300 100; do ((printf "Start $i: "; date; dd if=/dev/zero of=testfile_$i bs=1m count=$i 2>/dev/null; printf "End $i: "; date;)&) && sleep 1; done
Nur für den Fall, dass jemand noch interessiert ist, können Sie es tun, ohne eine Sub-Shell wie folgt aufrufen:
print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;
Sie können die Verwendung GNU parallel
Befehl zum ausführen von jobs in parallel.Es ist mehr sicher sind schneller.
Meine Vermutung ist, dass Sie versuchen, kopieren Sie mehrere große Dateien von der Quelle zum Ziel.Und für die, die Sie tun können, dass gleichzeitig mit der unten Anweisung.
$ ls *|parallel -kj0 --eta 'cp {} /tmp/destination'
Als wir verwendet haben -j0
option, alle Dateien werden kopiert in parallel.Im Fall, wenn Sie brauchen, um reduzieren Sie die Anzahl der parallelen Prozesse, dann können Sie verwenden -j<n>
wo <n>
ist die Anzahl der parallelen Prozess nicht ausgeführt werden kann.
Parallel sammeln auch den Ausgang des Prozesses und melden Sie es in einer sequentiellen Weise (mit -k
option), die andere job-control-Mechanismus kann nicht tun.
--eta
option wird geben Sie eine ausführliche Statistik der Prozess vor sich geht.So können wir wissen, wie der Prozess abgeschlossen haben und wie lange wird es dauern, um fertig zu werden.