bash -c "exec -a myProcessName ./script.sh &" はスクリプトをバックグラウンドに送信しません。

bash -c "exec -a myProcessName ./script.sh &" はスクリプトをバックグラウンドに送信しません。

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.shJava 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つのカスタム機能(emitKafkaトピックへのメッセージの送信と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.shsubmit_ecoemploi_ihm_back.shsubmit_ecoemploi_metier_back.sh

答え1

output=$(cmd &)

cmd &パイプを介してコードを実行するサブシェルの出力を収集します。サブシェルで開始されたすべてのプロセスは、非同期的に開始されるかどうかに関係なく、パイプを標準出力に継承します。

シェルはパイプのもう一方の端から読み取られ、パイプのファイルの端に達するまで拡張します。これは、パイプの書き込みの最後に開かれたすべてのファイル記述子(すべてのプロセスによって)が次の場合にのみ発生します。通常、すべてのプロセスが終了すると閉じます。

それにもかかわらず、プロセスが出力される前に戻ると、これらのプロセスの出力をキャプチャすることはできません。

残りの出力が必要ない場合は、非同期的に開始されたプロセスでstdoutを閉じて、そのパイプで開いたfdを解放できます。

たとえば、

output=$(sh -c 'echo some output; sleep 1; exec>&-; sleep 120' &)

121の代わりに1秒後に返され、shstdoutが閉じられた後にバックグラウンドから出て実行されます。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.bashexec -a name ./script.sh argexecve("./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 モードが有効になります。bashargv[0]argv[0]sh/sh

または:

BASH_ENV=./script.sh exec -a name bash -c ''

この場合はps -f表示されますが、環境で終了し、"name -c "他のbashスクリプト(それを含む)を起動するたびに平均が得られるため、無限再帰が発生する可能性があります。BASH_ENVscript.shbash -c inlinescript.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

関連情報