回答:
どうですか:
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
構文が異なるの異なるバージョンがあることに注意してください。たとえば、Debian派生物では、moreutils
パッケージにparallel
はまったく異なる動作をすると呼ばれる別のコマンドが含まれています。
parallel
使用してより良いですか&
?
で複数のプロセスを簡単に実行および強制終了できるようにしたい場合ctrl-c
、これは私のお気に入りの方法です。(…)
サブシェルで複数のバックグラウンドプロセスを生成し、トラップSIGINT
を実行kill 0
して、サブシェルグループで生成されたすべてを強制終了します。
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
複雑なプロセス実行構造を持つことができ、すべてが1つで終了します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(Linuxの)およびMacOSの/ 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
、並列で実行するコマンドの数を明示的に指定する必要がありますが、GNU xargs
では、できるだけ-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)は必要ない;
:-)
nohupを呼び出す非常に便利なプログラムがあります。
nohup - run a command immune to hangups, with output to a non-tty
nohup
それ自体はバックグラウンドで何も実行せず、使用nohup
はバックグラウンドでタスクを実行するための要件や前提条件ではありません。多くの場合、これらは一緒に使用すると便利ですが、それだけでは問題の解決にはなりません。
これは、最大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変数を使用できないため、プロセス間通信ファイルと基本的なflockセマフォを使用してクリティカルセクションを管理するため、少し難しくなります。もちろん、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/)、あなたは複数のだけでなく、実行することができますプロセス(他の人が提案方法)だけでなく、複数のスレッドをスクリプトから制御される1つの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では、スクリプトの子プロセスを待つことができます。