Bashスクリプトで3つのプロセスを開始し、後で停止コマンドを使用して停止できるように、各プロセスの名前を指定する必要があります。
# Démarrer les applications eco emploi : backend métier, backend du front (Java), et front (Angular)
demarrer_applications() {
emit "application" "start" "init" "Démarrage des applications ecoemploi" "Soumission des scripts de démarrage"
# Partie métier, backend Java
log "INFO" "Demande de démarrage de l'application métier ecoemploi (Backend Java)"
START_METIER=$(bash -c "exec -a $ECOEMPLOI_METIER_PROCESS_NAME ./submit_ecoemploi_metier_back.sh &")
if [ $? -ne 0 ]; then
emit "application" "start" "fail" "Soumission de ecoemploi backend métier échouée" "$START_METIER"
log "ERROR" "La demande de soumision de l'application métier ecoemploi (Backend Java) a échoué : $START_METIER"
exit $?
fi
# Partie front, backend Java
log "INFO" "Demande de démarrage de l'ihm ecoemploi (Backend Java)"
START_IHM_BACK=$(bash -c "exec -a $ECOEMPLOI_IHM_BACK_PROCESS_NAME ./submit_ecoemploi_ihm_back.sh &")
if [ $? -ne 0 ]; then
emit "application" "start" "fail" "Soumission de ecoemploi backend ihm échouée" "$START_IHM_BACK"
log "ERROR" "La demande de soumision de l'application ihm ecoemploi (Backend Java) a échoué : $START_IHM_BACK"
exit $?
fi
log "INFO" "Demande de démarrage de l'ihm ecoemploi (Front Angular)"
START_IHM_FRONT=$(bash -c "exec -a $ECOEMPLOI_IHM_FRONT_PROCESS_NAME ./submit_ecoemploi_ihm_front.sh &")
if [ $? -ne 0 ]; then
emit "application" "start" "fail" "Soumission de ecoemploi ihm front échouée" "$START_IHM_FRONT"
log "ERROR" "La demande de soumision de l'application ihm ecoemploi (Front Angular) a échoué : $START_IHM_FRONT"
exit $?
fi
log "INFO" "Les demandes de soumission des applications ont été faites."
}
スクリプトを要約するために、次のコマンドを実行しようとします。
bash -c "exec -a $ECOEMPLOI_METIER_PROCESS_NAME ./submit_ecoemploi_metier_back.sh &"
bash -c "exec -a $ECOEMPLOI_IHM_BACK_PROCESS_NAME ./submit_ecoemploi_ihm_back.sh &"
bash -c "exec -a $ECOEMPLOI_IHM_BACK_PROCESS_NAME ./submit_ecoemploi_ihm_back.sh &"
各提出添え字には、次の形式があります。
#!/bin/bash
source ecoemploi-start-stop-common.sh
cd "$ECOEMPLOI_METIER_HOME"
if [ $? -ne 0 ]; then
emit "application" "start" "fail" "Le répertoire d'installation de l'application métier, $ECOEMPLOI_METIER_HOME, est absent" ""
log "ERROR" "Le répertoire d'installation de l'application métier, $ECOEMPLOI_METIER_HOME, est absent"
exit $?
fi
./start.sh
たとえば、次はstart.sh
Java 17アプリケーションを起動します。
java --add-exports java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.nio=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.invoke=ALL-UNNAMED \
-jar target/application-metier-et-gestion.jar
これには、ecoemploi-start-stop-common.sh
いくつかのディレクトリの場所と2つのカスタム機能(emit
Kafkaトピックへのメッセージの送信とlog
コンソールへのログイン)が定義されています。
#!/bin/bash
#
# Répertoires d'installation de l'application, et noms des processus qui vont être lancés par bash/exec
ECOEMPLOI_HOME="/home/lebihan/dev/Java/comptes-france"
ECOEMPLOI_METIER_HOME="$ECOEMPLOI_HOME/metier-et-gestion/ApplicationMetierEtGestion"
ECOEMPLOI_IHM_FRONT_HOME="$ECOEMPLOI_HOME/web-client/ApplicationEtude/etude"
ECOEMPLOI_IHM_BACK_HOME="$ECOEMPLOI_HOME/web-client/ApplicationEtude"
ECOEMPLOI_METIER_PROCESS_NAME="ecoemploi_backend_metier"
ECOEMPLOI_IHM_BACK_PROCESS_NAME="ecoemploi_ihm_backend"
ECOEMPLOI_IHM_FRONT_PROCESS_NAME="ecoemploi_ihm_front"
# Communication avec Kafka
KAFKA_BOOTSTRAP_SERVER_PORT=9092
BOOTSTRAP_SERVER="localhost:$KAFKA_BOOTSTRAP_SERVER_PORT"
TOPIC_VIE="ecoemploi-statut"
# Logger un message, horodaté
# $1 Sevérité
# $2 Message
log() {
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
if [ "$1" = "ERROR" ]; then
echo "$TIMESTAMP [$1] $2" >&2
else
echo "$TIMESTAMP [$1] $2"
fi
}
# Emettre un évènement dans le $TOPIC_VIE de Kafka
# $1 : Composant
# $2 : Phase : init, start
# $3 : Statut : start, fail
# $4 : description
# $5 : Message
emit() {
# Laisser la ligne ci-dessous non indentée pour que EOF fonctionne.
MESSAGE_EMIT_KAFKA=$(cat << EOF
{
"composant": "$1",
"phase": "$2",
"statut": "$3",
"description": "$4",
"message": "$5"
}
EOF
)
MESSAGE_EMISSION_VERS_KAFKA=$(echo "$MESSAGE_EMIT_KAFKA" | kafka-console-producer.sh --broker-list $BOOTSTRAP_SERVER --topic $TOPIC_VIE)
if [ $? -ne 0 ]; then
log "WARN" "Le message vers le topic $TOPIC_VIE n'a pu être émis : $MESSAGE_EMISSION_VERS_KAFKA"
fi
}
私の問題は、demarrer_applications()
他のいくつかの関数の後に呼び出され、最後の[INFO]ログを生成する私のbash関数で、
2023-04-14 10:01:09 [INFO] Démarrage de Zookeeper puis de Kafka...
2023-04-14 10:01:09 [INFO] Zookeeper et Kafka ont démarré.
2023-04-14 10:01:10 [INFO] Le topic ecoemploi-statut existant sera réutilisé sur Kafka localhost:9092.
2023-04-14 10:01:11 [INFO] Postgresql n'est pas démarré. Démarrage en cours...
2023-04-14 10:01:13 [INFO] Postgresql est prêt.
2023-04-14 10:01:14 [INFO] Demande de démarrage de l'application métier ecoemploi (Backend Java)
次のコマンドを使用して必要なアプリケーションを実行します。
bash -c "exec -a $ECOEMPLOI_METIER_PROCESS_NAME ./submit_ecoemploi_metier_back.sh &"
ただし、&
後で./submit_ecoemploi_metier_back.sh
アプリはバックグラウンドで送信されません。私のデフォルトスクリプトは操作を続行できず、次のアプリケーションを起動できません。ここで停止してCtrl-Cを待ちます。
submit_ecoemploi_*.sh
バックグラウンドでコマンドを使用してbash
スクリプトを送信するにはどうすればよいですかexec
?ありがとうございます!
@StéphaneChazelas
私はあなたのソリューションを使って私の機能を調整しました(ここには変更された行だけを入れました)。
demarrer_applications() {
# Partie métier, backend Java
NAME=$ECOEMPLOI_METIER_PROCESS_NAME bash -c 'exec -a "$NAME" ./submit_ecoemploi_metier_back.sh &'
NAME=$ECOEMPLOI_IHM_BACK_PROCESS_NAME bash -c 'exec -a "$NAME" ./submit_ecoemploi_ihm_back.sh &'
NAME=$ECOEMPLOI_IHM_FRONT_PROCESS_NAME bash -c 'exec -a "$NAME" ./submit_ecoemploi_ihm_front.sh &'
}
完全に提出され、私のアプリケーションは3つのコンポーネントを起動し、利用可能とマークされています。
しかし、aはps -f
私に次のように返します。
UID PID PPID C STIME TTY TIME CMD
lebihan 309213 309207 0 11:18 pts/0 00:00:00 bash
lebihan 322835 2710 21 11:26 pts/0 00:00:04 java -Xmx1G -Xms1G -server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ExplicitGCInvokesConcurrent -XX:Ma
lebihan 324800 2710 0 11:27 pts/0 00:00:00 /bin/bash /home/lebihan/dev/Java/comptes-france/submit_ecoemploi_metier_back.sh
lebihan 324803 2710 0 11:27 pts/0 00:00:00 /bin/bash /home/lebihan/dev/Java/comptes-france/submit_ecoemploi_ihm_back.sh
lebihan 324804 324800 0 11:27 pts/0 00:00:00 /bin/bash ./start.sh
lebihan 324806 324803 0 11:27 pts/0 00:00:00 /bin/bash ./start.sh
lebihan 324808 324804 99 11:27 pts/0 00:00:47 java --add-exports java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --
lebihan 324809 2710 0 11:27 pts/0 00:00:00 /bin/bash /home/lebihan/dev/Java/comptes-france/submit_ecoemploi_ihm_front.sh
lebihan 324811 324806 52 11:27 pts/0 00:00:07 java --add-exports java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --
lebihan 324812 324809 0 11:27 pts/0 00:00:00 /bin/bash ./start.sh
lebihan 324814 324812 51 11:27 pts/0 00:00:07 ng serve
lebihan 325316 309213 0 11:27 pts/0 00:00:00 ps -f
プロセス名が変更されるのを見ることはできません。
これにより、停止コマンドで停止できませんsubmit_ecoemploi_ihm_front.sh
。submit_ecoemploi_ihm_back.sh
submit_ecoemploi_metier_back.sh
答え1
output=$(cmd &)
cmd &
パイプを介してコードを実行するサブシェルの出力を収集します。サブシェルで開始されたすべてのプロセスは、非同期的に開始されるかどうかに関係なく、パイプを標準出力に継承します。
シェルはパイプのもう一方の端から読み取られ、パイプのファイルの端に達するまで拡張します。これは、パイプの書き込みの最後に開かれたすべてのファイル記述子(すべてのプロセスによって)が次の場合にのみ発生します。通常、すべてのプロセスが終了すると閉じます。
それにもかかわらず、プロセスが出力される前に戻ると、これらのプロセスの出力をキャプチャすることはできません。
残りの出力が必要ない場合は、非同期的に開始されたプロセスでstdoutを閉じて、そのパイプで開いたfdを解放できます。
たとえば、
output=$(sh -c 'echo some output; sleep 1; exec>&-; sleep 120' &)
121の代わりに1秒後に返され、sh
stdoutが閉じられた後にバックグラウンドから出て実行されます。sleep 120
exec>&-
exec>/dev/null
パイプも閉じるfdを使用するよりも優れていますが、stdoutを閉じたままにしないでください。アプリケーションは通常開いていると予想しているため、これは一般的に悪い考えです。
同時に実行される複数のコマンドの出力をキャプチャしたい場合は、変数とコマンドの置換を使用してこれを行うことはできません。同様の機能select
をサポートしていないbashでは、一時poll
ファイルを使用することをお勧めします。
exec -a name1 cmd1 > "$temp1" &
exec -a name2 cmd2 > "$temp2" &
exec -a name3 cmd3 > "$temp3" &
wait
output1=$(<"$temp1")
output2=$(<"$temp2")
output3=$(<"$temp3")
(bashを仮定)。
ここではそうする必要はありませんbash -c ...
。ところで:
bash -c "exec -a $ECOEMPLOI_METIER_PROCESS_NAME ./submit_ecoemploi_metier_back.sh &"
内容がECOEMPLOI_METIER_PROCESS_NAME
望むものではなく、bashコードとして解釈されるので、間違っています。必要なものはパラメータとして扱う必要があるため、-a
次のようにする必要があります。
NAME=$ECOEMPLOI_METIER_PROCESS_NAME bash -c '
exec -a "$NAME" ./submit_ecoemploi_metier_back.sh &'
または:
bash -c '"$@" &' bash exec -a "$ECOEMPLOI_METIER_PROCESS_NAME" ./submit_ecoemploi_metier_back.sh
bash -c
しかし、これがbashスクリプトであれば完全に重複します。ただし:
exec -a "$ECOEMPLOI_METIER_PROCESS_NAME" ./submit_ecoemploi_metier_back.sh &
とにかくshebangをscript.sh
実行すると(サフィックスがあるかどうかにかかわらず、サフィックスは誤解を招く可能性があります)、asシェルはaを実行しますが、これはスクリプトなので、少なくともLinuxでは順次実行され失われます。#! /bin/bash
.sh
.bash
exec -a name ./script.sh arg
execve("./script.sh", ["name", "arg"], env)
execve("/bin/bash", ["/bin/bash", "./script.sh", "arg"], env)
name
あなたはそれを使用することができます:
exec -a name bash ./script.sh
この場合、ps -f
受信した情報に基づいて動作を調整できますname ./script.sh
。たとえば、 of または it で終わると、POSIX モードが有効になります。bash
argv[0]
argv[0]
sh
/sh
または:
BASH_ENV=./script.sh exec -a name bash -c ''
この場合はps -f
表示されますが、環境で終了し、"name -c "
他のbashスクリプト(それを含む)を起動するたびに平均が得られるため、無限再帰が発生する可能性があります。BASH_ENV
script.sh
bash -c inline
script.sh
答え2
あなたが説明したものほとんど効果的私のため。ところで小さな部分一つを変えなければなりませんでした。私の仕事の例は次のとおりです。
1. 内容script.sh
#!/bin/bash
while [ -f /tmp/script.run ] # Run only while this file exists
do
date >/tmp/script.date 2>&1 # Update the output file
sleep 0.5 # Pause briefly
done
rm -f /tmp/script.date
今提案したとおりに実行します。
touch /tmp/script.run
bash -c "exec -a myProcessName ./script.sh & "
プロセスツリーを見てみましょうps -f
UID PID PPID C STIME TTY TIME CMD
roaima 9301 9296 0 09:41 pts/0 00:00:00 -bash
roaima 9913 1 0 09:46 pts/0 00:00:00 /bin/bash /home/roaima/script.sh
roaima 9919 9913 0 09:46 pts/0 00:00:00 sleep 0.5
roaima 9920 9301 0 09:46 pts/0 00:00:00 ps -f
そのプロセス(PID 9913、9919)が実行されていることがわかりますが、まだプロセス名が適用されていません。これはスクリプトであり、そのスクリプトはその行にリストされているプロセスによって実行されるためです#!
。
プロセスを停止してしばらく待ってから、もう一度やり直してみましょう。
rm -f /tmp/script.run # Remove the flag file
ps -f # Confirm the process has ended
touch /tmp/script.run
bash -c "exec -a myProcessName bash ./script.sh & "
この明示的な呼び出しは、期待bash
どおりに名前が変更されました。
UID PID PPID C STIME TTY TIME CMD
roaima 9301 9296 0 09:41 pts/0 00:00:00 -bash
roaima 11745 1 2 09:53 pts/0 00:00:00 myProcessName ./script.sh
roaima 11777 11745 0 09:53 pts/0 00:00:00 sleep 0.5
roaima 11778 9301 0 09:53 pts/0 00:00:00 ps -f
ただし、実際には外部の電話を避けてbash
直接電話をかけることもできますexec
。
exec -a myProcessName bash ./script.sh &
最後に、プロセスを追跡するより良い方法は、プロセス名ではなくPIDを使用することです。
./script.sh &
scriptPID=$!
kill -0 $scriptPID && echo "The script is still running with PID $scriptPID"
フラグファイルを削除して/tmp/script.run
しばらく停止した後、kill … && echo …
コマンドを繰り返します。スクリプトが実行されなくなったため、出力はありません。
答え3
Roaimaがこの有名な場所について書いたのと似ています。
# Initialize a file for collecting background process numbers:
sync_file=/tmp/syncfile.123
printf "" > $sync_file
# Repeat this block for all your parallel commands:
# This can be a loop or a fixed number of process submissions
# Run your command(s) in a sub-shell:
(
# Name your process using a single word:
pname=MyProcess.1
# Save the name and PID of the bg process
printf "$pname:$?\n" >> $sync_file
# run your command(s)
my_command
) &
# End block
# This part can be run in a separate script:
# Kill your processes using PID list you have stored in the file
sync_file=/tmp/syncfile.123
for a in $( cat $sync_file )
do
procname=${a%:*} # Get the process name
pid=${a#*:} # Get the PID
echo "Process: $procname PID: $pid"
kill -9 $pid
done