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?

War es hilfreich?

Lösung

Ich habe nicht dieses aber, wie etwa

getestet
print `(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

zu erfassen hat

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top