[Bash] Schleife mit Ausführung von genau 2 Prozessen

Raubsau

NGBler
Registriert
29 Aug. 2013
Beiträge
197
Hallo,

folgendes funktioniert so, wie es hier steht - jede Datei wird als Argument an ein Programm übergeben und abgearbeitet, dann die nächste Datei etc.

[src=bash]for DATEI in ~/*.txt
do
./program $DATEI
done
wait[/src]

Ich hätte gerne, dass immer 2 Prozesse laufen.
Also soll der Prozess für Datei 1 und 2 gestartet werden, und wenn 1 oder 2 fertig sind, soll der Prozess für Datei 3 gestartet werden usw., bis alle Dateien übergeben wurden.
Es würde auch schon reichen, wenn Datei 1 und 2 abgearbeitet werden, dann Datei 3 und 4 parallel usw.

Ich weiß nicht, wie ich den Index für $DATEI erhöhen kann - daran hapert es gerade.
Ich habe herausgefunden, dass ich mit while-loops solche Parallelisierung anstoßen kann - da fällt mir aber keine Bedingung ein, nach der ich die Schleife steuern könnte.

Könnt ihr mir die nötigen Stichworte nennen?

Danke

Raubsau
 
Mir fällt dazu spontan "parallel" ein, ist n GNU tool und erspart die das in bash zu implementieren.

du übergibst ein Kommando und eine Parameterliste, die Anzahl der parallel auszuführenden jobs kann mit dem Parameter "-j n" bestimmt werden.

Schau dir am besten einfach mal die manpage an um zu gucken obs für dein use case past.
 
  • Thread Starter Thread Starter
  • #3
Sehr interessantes Programm, danke :)
Sobald ich mehrere Computer zur Verfügung habe, werde ich mich damit auseinander setzen (müssen).

"parallel" ist glaube ich overkill, ich habe Stunden gebraucht, um das Skript (oben ist nur ein Ausschnitt) zum Laufen zu bekommen. Wenn ich jetzt noch Regex lernen soll, kann ichs auch gleich per Hand anstoßen.

Das Programm (./program) nutzt nur einen Kern, dashalb würde ich gern 2 Prozesse auf einmal laufen lassen.
 
Hab da mal was zusammen gebastelt... quick and dirty... aber sollte laufen
[src=bash]
#!/bin/bash


function IsOneOfTheProcessesEnded {
PID1=$1
PID2=$2
cnt=0
cmd="ps -p $PID1"
lines=`$cmd | wc -l`
if [ $lines -eq 2 ]
then
let cnt=$cnt+1
fi

cmd="ps -p $PID2"
lines=`$cmd | wc -l`
if [ $lines -eq 2 ]
then
let cnt=$cnt+1
fi

if [ $cnt -eq 2 ]
then
return 0
else
return 1
fi

}





SWITCH=0

PID1=999999999
PID2=999999999

li="1 2 3 4 5 6 7 8 9"

#for DATEI in ~/*.txt
for DATEI in $li
do


tx=`IsOneOfTheProcessesEnded $PID1 $PID2`
ty=$?

while [ $ty -eq 0 ]
do
sleep 0.1
tx=`IsOneOfTheProcessesEnded $PID1 $PID2`
ty=$?
done





echo "STARTING $DATEI"


#./program $DATEI &

ping -c7 google.de >/dev/null &


tmp=$!
if [ $SWITCH -eq 0 ]
then
SWITCH=1
PID1=$tmp
echo "SET PID1 $tmp"
else
SWITCH=0
PID2=$tmp
echo "SET PID2 $tmp"
fi





done







[/src]
 
  • Thread Starter Thread Starter
  • #5
Danke, ich wühle mich da mal durch.

Mein Ansatz wäre gewesen, durch den Aufruf 1 initialen Skripts 2 Unterskripte zu starten.
Jedes Skript würde sich die erste Datei im Verzeichnis ins eigene Verzeichnis bewegen, abarbeiten, die nächste "erste" Datei holen usw.
Das initiale Skript würde warten, bis beide Skripte beendet sind und die Schritte durchführen, die erst mit dem kompletten Output abgearbeitet werden können. Slow & dirty ;)
 
Du brauchst eigentlich nur

#for DATEI in ~/*.txt
und
#./program $DATEI &
aktiv zu setzen, und dafür die Zeilen
for DATEI in $li
ping -c7 google.de >/dev/null &
auskommentieren.

wobei ich
./program "$DATEI" >/dev/null &
verwenden würde.

Und wenn in den Dateinamen Leerzeichen auftauchen sollten, dann würde ich noch den
[src=bash]IFS="
"[/src]
setzen, damit for nicht stolpert.... fertig könnte es z.b. so aussehen ;) :
[src=bash]#!/bin/bash

MYIFS=$IFS
IFS="
"


function IsOneOfTheProcessesEnded {
PID1=$1
PID2=$2
cnt=0
cmd="ps -p $PID1"
lines=`$cmd | wc -l`
if [ $lines -eq 2 ]
then
let cnt=$cnt+1
fi

cmd="ps -p $PID2"
lines=`$cmd | wc -l`
if [ $lines -eq 2 ]
then
let cnt=$cnt+1
fi

if [ $cnt -eq 2 ]
then
return 0
else
return 1
fi

}


SWITCH=0

PID1=999999999
PID2=999999999


for DATEI in ~/*.txt
do


tx=`IsOneOfTheProcessesEnded $PID1 $PID2`
ty=$?

while [ $ty -eq 0 ]
do
sleep 0.1
tx=`IsOneOfTheProcessesEnded $PID1 $PID2`
ty=$?
done



./program "$DATEI" &


tmp=$!
if [ $SWITCH -eq 0 ]
then
SWITCH=1
PID1=$tmp
else
SWITCH=0
PID2=$tmp
fi


done


IFS=$MYIFS
[/src]
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #7
Hallo,

mit xargs ist mein Problem gelöst:

Code:
Expand Collapse Copy
# Finde Dateien
find . -name "datei*" -print
# Programmaufruf
./program
# Übergeben jeder gefundenen Datei einzeln
find . -name "datei*" -print | xargs -n1 ./program 
# Übergeben jeder gefundenen Datei einzeln und ausführen von 2 Prozessen gleichzeitig:
find . -name "datei*" -print | xargs -n1 -P2 ./program
 
Zurück
Oben