답변:
어때요?
prog1 & prog2 && fg
이것은 :
prog1
.prog2
하고 전경에 유지하면 다음과 같이 닫을 수 있습니다.ctrl-c
.prog2
, 당신에게 돌아갑니다 prog1
'의 전경 도 가까이 함께 할 수있는 당신은 그래서 ctrl-c
.prog1
때 prog2
종료는? 생각해보십시오 node srv.js & cucumberjs
prog1 & prog2 ; fg
이 이루어졌습니다. 여러 ssh 터널을 한 번에 실행하기위한 것입니다. 이것이 누군가를 돕기를 바랍니다.
prog2
즉시 실행되지 않으면 prog1
포 그라운드로 돌아가는 효과가 있습니다. 이것이 바람직하다면 괜찮습니다.
prog1 & prog2 && kill $!
입니다.
당신은 사용할 수 있습니다 wait
:
some_command &
P1=$!
other_command &
P2=$!
wait $P1 $P2
백그라운드 프로그램 PID를 변수 ( $!
마지막으로 시작된 프로세스 PID)에 할당 한 다음 wait
명령이 대기합니다. 스크립트를 죽이면 프로세스도 죽이기 때문에 좋습니다!
#!/usr/bin/env bash ARRAY='cat bat rat' for ARR in $ARRAY do ./run_script1 $ARR & done P1=$! wait $P1 echo "INFO: Execution of all background processes in the for loop has completed.."
${}
문자열 목록 또는 유사한 것으로 보간하는 데 사용해야한다고 생각합니다 .
GNU Parallel http://www.gnu.org/software/parallel/을 사용하면 다음과 같이 쉽습니다.
(echo prog1; echo prog2) | parallel
또는 원하는 경우 :
parallel ::: prog1 prog2
더 알아보기:
parallel
구문 이 다른 버전이 있다는 점은 주목할 가치가 있습니다. 예를 들어, 데비안 파생물에서 moreutils
패키지는 parallel
상당히 다르게 동작 하는 다른 명령을 포함합니다 .
parallel
사용하는 것보다 더 나은 &
?
를 사용하여 여러 프로세스를 쉽게 실행하고 종료하려면 ctrl-c
이것이 내가 가장 좋아하는 방법입니다. 하위 셸에서 여러 백그라운드 프로세스를 생성 (…)
하고 trap SIGINT
을 실행 kill 0
하면 하위 셸 그룹에 생성 된 모든 것이 종료됩니다.
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
복잡한 프로세스 실행 구조를 가질 수 있으며 모든 것이 단일으로 닫힙니다 ctrl-c
(마지막 프로세스가 포 그라운드에서 실행되도록하십시오 (즉, &
after를 포함하지 마십시오 prog1.3
)).
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
xargs -P <n>
당신이 실행할 수 있습니다 <n>
명령을 병렬 .
동안 -P
비표준 옵션이며, 모두 GNU (리눅스) 및 맥 OS / BSD 구현을 지원합니다.
다음 예제는
time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
결과는 다음과 같습니다.
1 # output from 1st command
4 # output from *last* command, which started as soon as the count dropped below 3
2 # output from 2nd command
3 # output from 3rd command
real 0m3.012s
user 0m0.011s
sys 0m0.008s
타이밍은 명령이 병렬로 실행되었음을 나타냅니다 (마지막 명령은 원본 3 중 첫 번째가 종료 된 후에 만 시작되었지만 매우 빠르게 실행 됨).
xargs
모든 명령이 완료 될 때까지 명령 자체는 반환하지 않습니다,하지만 당신은 제어 연산자를 종료하여 백그라운드에서 그것을 실행할 수 &
사용하여 다음과 wait
전체 기다릴 내장을 xargs
명령을 완료 할 수 있습니다.
{
xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &
# Script execution continues here while `xargs` is running
# in the background.
echo "Waiting for commands to finish..."
# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!
노트 :
BSD / macOS xargs
를 사용하려면 명령 수를 명시 적으로 병렬 로 실행 xargs
해야 하지만 GNU 에서는 최대한 병렬 로-P 0
실행 하도록 지정할 수 있습니다 .
병렬로 실행되는 프로세스의 출력은 생성 될 때 도착 하므로 예기치 않게 인터리브 됩니다.
parallel
에서 언급했듯이 GNU 는 프로세스별로 출력을 편리하게 직렬화 (그룹화)하고 더 많은 고급 기능을 제공합니다.#!/bin/bash
prog1 & 2> .errorprog1.log; prog2 & 2> .errorprog2.log
별도의 로그로 오류를 리디렉션하십시오.
prog1 2> .errorprog1.log & prog2 2> .errorprog2.log &
ls notthere1 & 2> .errorprog1.log; ls notthere2 & 2>.errorprog2.log
. 오류는 콘솔로 이동하고 두 오류 파일이 모두 비어 있습니다. @Dennis Williamson이 말했듯 &
이,와 같은 구분 기호 ;
이므로 (a) 명령 끝에서 (리디렉션 후) 가야하며 (b) 전혀 필요하지 않습니다 ;
:-)
max n 프로세스를 병렬로 실행하기 위해 사용하는 함수는 다음과 같습니다 (이 예에서는 n = 4).
max_children=4
function parallel {
local time1=$(date +"%H:%M:%S")
local time2=""
# for the sake of the example, I'm using $2 as a description, you may be interested in other description
echo "starting $2 ($time1)..."
"$@" && time2=$(date +"%H:%M:%S") && echo "finishing $2 ($time1 -- $time2)..." &
local my_pid=$$
local children=$(ps -eo ppid | grep -w $my_pid | wc -w)
children=$((children-1))
if [[ $children -ge $max_children ]]; then
wait -n
fi
}
parallel sleep 5
parallel sleep 6
parallel sleep 7
parallel sleep 8
parallel sleep 9
wait
max_children이 코어 수로 설정되면이 기능은 유휴 코어를 피하려고 시도합니다.
wait -n
필요로 bash
4.3를 하며 기다리고에 논리를 변경 어떤 종료하려면 지정된 / 암시 프로세스.
나는 최근에 동시에 여러 프로그램을 실행하고 출력을 분리 된 로그 파일로 리디렉션하고 완료 될 때까지 기다려야하는 비슷한 상황을 겪었습니다.
#!/bin/bash
# Add the full path processes to run to the array
PROCESSES_TO_RUN=("/home/joao/Code/test/prog_1/prog1" \
"/home/joao/Code/test/prog_2/prog2")
# You can keep adding processes to the array...
for i in ${PROCESSES_TO_RUN[@]}; do
${i%/*}/./${i##*/} > ${i}.log 2>&1 &
# ${i%/*} -> Get folder name until the /
# ${i##*/} -> Get the filename after the /
done
# Wait for the processes to finish
wait
출처 : http://joaoperibeiro.com/execute-multiple-programs-and-redirect-their-outputs-linux/
프로세스 생성 관리자
물론 기술적으로는 프로세스이며,이 프로그램은 실제로 프로세스 스폰 관리자라고합니다. 그러나 이것은 앰퍼샌드를 사용하여 포크 할 때 BASH가 작동하는 방식 때문일뿐입니다. fork () 또는 아마도 clone () 시스템 호출을 사용합니다 메모리를 공유하는 pthread_create ()와 같은 것이 아니라 별도의 메모리 공간으로 복제됩니다. 만약 BASH가 후자를 지원한다면, 각각의 "시퀀스 실행"은 동일하게 작동 할 것이며보다 효율적인 메모리 풋 프린트를 얻는 동안 전통적인 스레드라고 할 수 있습니다. 그러나 GLOBAL 변수를 각 작업자 복제에서 사용할 수 없으므로 프로세스 간 통신 파일과 초보적 무리 세마포어를 사용하여 중요한 섹션을 관리하기 때문에 기능적으로 동일하게 작동합니다. 물론 BASH에서 포크하는 것이 기본적인 대답이지만 사람들은 그것을 알고있는 것처럼 느껴지지만 실제로 포크를하고 잊어 버리지 않고 생성 된 것을 관리하려고합니다. 이는 단일 리소스에 액세스하는 최대 200 개의 분기 프로세스 인스턴스를 관리하는 방법을 보여줍니다. 분명히 이것은 과잉입니다. 그러나 나는 그것을 계속 쓰는 것을 즐겼습니다. 이에 따라 터미널 크기를 늘리십시오. 이 정보가 도움이 되길 바랍니다.
ME=$(basename $0)
IPC="/tmp/$ME.ipc" #interprocess communication file (global thread accounting stats)
DBG=/tmp/$ME.log
echo 0 > $IPC #initalize counter
F1=thread
SPAWNED=0
COMPLETE=0
SPAWN=1000 #number of jobs to process
SPEEDFACTOR=1 #dynamically compensates for execution time
THREADLIMIT=50 #maximum concurrent threads
TPS=1 #threads per second delay
THREADCOUNT=0 #number of running threads
SCALE="scale=5" #controls bc's precision
START=$(date +%s) #whence we began
MAXTHREADDUR=6 #maximum thread life span - demo mode
LOWER=$[$THREADLIMIT*100*90/10000] #90% worker utilization threshold
UPPER=$[$THREADLIMIT*100*95/10000] #95% worker utilization threshold
DELTA=10 #initial percent speed change
threadspeed() #dynamically adjust spawn rate based on worker utilization
{
#vaguely assumes thread execution average will be consistent
THREADCOUNT=$(threadcount)
if [ $THREADCOUNT -ge $LOWER ] && [ $THREADCOUNT -le $UPPER ] ;then
echo SPEED HOLD >> $DBG
return
elif [ $THREADCOUNT -lt $LOWER ] ;then
#if maxthread is free speed up
SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1-($DELTA/100))"|bc)
echo SPEED UP $DELTA%>> $DBG
elif [ $THREADCOUNT -gt $UPPER ];then
#if maxthread is active then slow down
SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1+($DELTA/100))"|bc)
DELTA=1 #begin fine grain control
echo SLOW DOWN $DELTA%>> $DBG
fi
echo SPEEDFACTOR $SPEEDFACTOR >> $DBG
#average thread duration (total elapsed time / number of threads completed)
#if threads completed is zero (less than 100), default to maxdelay/2 maxthreads
COMPLETE=$(cat $IPC)
if [ -z $COMPLETE ];then
echo BAD IPC READ ============================================== >> $DBG
return
fi
#echo Threads COMPLETE $COMPLETE >> $DBG
if [ $COMPLETE -lt 100 ];then
AVGTHREAD=$(echo "$SCALE;$MAXTHREADDUR/2"|bc)
else
ELAPSED=$[$(date +%s)-$START]
#echo Elapsed Time $ELAPSED >> $DBG
AVGTHREAD=$(echo "$SCALE;$ELAPSED/$COMPLETE*$THREADLIMIT"|bc)
fi
echo AVGTHREAD Duration is $AVGTHREAD >> $DBG
#calculate timing to achieve spawning each workers fast enough
# to utilize threadlimit - average time it takes to complete one thread / max number of threads
TPS=$(echo "$SCALE;($AVGTHREAD/$THREADLIMIT)*$SPEEDFACTOR"|bc)
#TPS=$(echo "$SCALE;$AVGTHREAD/$THREADLIMIT"|bc) # maintains pretty good
#echo TPS $TPS >> $DBG
}
function plot()
{
echo -en \\033[${2}\;${1}H
if [ -n "$3" ];then
if [[ $4 = "good" ]];then
echo -en "\\033[1;32m"
elif [[ $4 = "warn" ]];then
echo -en "\\033[1;33m"
elif [[ $4 = "fail" ]];then
echo -en "\\033[1;31m"
elif [[ $4 = "crit" ]];then
echo -en "\\033[1;31;4m"
fi
fi
echo -n "$3"
echo -en "\\033[0;39m"
}
trackthread() #displays thread status
{
WORKERID=$1
THREADID=$2
ACTION=$3 #setactive | setfree | update
AGE=$4
TS=$(date +%s)
COL=$[(($WORKERID-1)/50)*40]
ROW=$[(($WORKERID-1)%50)+1]
case $ACTION in
"setactive" )
touch /tmp/$ME.$F1$WORKERID #redundant - see main loop
#echo created file $ME.$F1$WORKERID >> $DBG
plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID INIT " good
;;
"update" )
plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID AGE:$AGE" warn
;;
"setfree" )
plot $COL $ROW "Worker$WORKERID: FREE " fail
rm /tmp/$ME.$F1$WORKERID
;;
* )
;;
esac
}
getfreeworkerid()
{
for i in $(seq 1 $[$THREADLIMIT+1])
do
if [ ! -e /tmp/$ME.$F1$i ];then
#echo "getfreeworkerid returned $i" >> $DBG
break
fi
done
if [ $i -eq $[$THREADLIMIT+1] ];then
#echo "no free threads" >> $DBG
echo 0
#exit
else
echo $i
fi
}
updateIPC()
{
COMPLETE=$(cat $IPC) #read IPC
COMPLETE=$[$COMPLETE+1] #increment IPC
echo $COMPLETE > $IPC #write back to IPC
}
worker()
{
WORKERID=$1
THREADID=$2
#echo "new worker WORKERID:$WORKERID THREADID:$THREADID" >> $DBG
#accessing common terminal requires critical blocking section
(flock -x -w 10 201
trackthread $WORKERID $THREADID setactive
)201>/tmp/$ME.lock
let "RND = $RANDOM % $MAXTHREADDUR +1"
for s in $(seq 1 $RND) #simulate random lifespan
do
sleep 1;
(flock -x -w 10 201
trackthread $WORKERID $THREADID update $s
)201>/tmp/$ME.lock
done
(flock -x -w 10 201
trackthread $WORKERID $THREADID setfree
)201>/tmp/$ME.lock
(flock -x -w 10 201
updateIPC
)201>/tmp/$ME.lock
}
threadcount()
{
TC=$(ls /tmp/$ME.$F1* 2> /dev/null | wc -l)
#echo threadcount is $TC >> $DBG
THREADCOUNT=$TC
echo $TC
}
status()
{
#summary status line
COMPLETE=$(cat $IPC)
plot 1 $[$THREADLIMIT+2] "WORKERS $(threadcount)/$THREADLIMIT SPAWNED $SPAWNED/$SPAWN COMPLETE $COMPLETE/$SPAWN SF=$SPEEDFACTOR TIMING=$TPS"
echo -en '\033[K' #clear to end of line
}
function main()
{
while [ $SPAWNED -lt $SPAWN ]
do
while [ $(threadcount) -lt $THREADLIMIT ] && [ $SPAWNED -lt $SPAWN ]
do
WID=$(getfreeworkerid)
worker $WID $SPAWNED &
touch /tmp/$ME.$F1$WID #if this loops faster than file creation in the worker thread it steps on itself, thread tracking is best in main loop
SPAWNED=$[$SPAWNED+1]
(flock -x -w 10 201
status
)201>/tmp/$ME.lock
sleep $TPS
if ((! $[$SPAWNED%100]));then
#rethink thread timing every 100 threads
threadspeed
fi
done
sleep $TPS
done
while [ "$(threadcount)" -gt 0 ]
do
(flock -x -w 10 201
status
)201>/tmp/$ME.lock
sleep 1;
done
status
}
clear
threadspeed
main
wait
status
echo
스크립트는 다음과 같아야합니다.
prog1 &
prog2 &
.
.
progn &
wait
progn+1 &
progn+2 &
.
.
시스템이 한 번에 n 개의 작업을 수행 할 수 있다고 가정합니다. 한 번에 n 개의 작업 만 실행하려면 wait를 사용하십시오.
함께 bashj ( https://sourceforge.net/projects/bashj/ ), 당신은뿐만 아니라 여러 실행할 수 있어야합니다 프로세스 (방법의 다른 제안)뿐만 아니라 다수의 스레드 스크립트에서 제어 하나의 JVM에서. 그러나 물론 이것은 Java JDK가 필요합니다. 스레드는 프로세스보다 적은 리소스를 사용합니다.
작동 코드는 다음과 같습니다.
#!/usr/bin/bashj
#!java
public static int cnt=0;
private static void loop() {u.p("java says cnt= "+(cnt++));u.sleep(1.0);}
public static void startThread()
{(new Thread(() -> {while (true) {loop();}})).start();}
#!bashj
j.startThread()
while [ j.cnt -lt 4 ]
do
echo "bash views cnt=" j.cnt
sleep 0.5
done
wait
! bash에서는 스크립트의 자식 프로세스를 기다릴 수 있습니다.