bash -c "exec -a myProcessName ./script.sh &"는 스크립트를 백그라운드로 보내지 않습니다.

bash -c "exec -a myProcessName ./script.sh &"는 스크립트를 백그라운드로 보내지 않습니다.

Bash 스크립트에서 세 개의 프로세스를 시작하고 나중에 중지 명령을 사용하여 중지할 수 있도록 각 프로세스의 이름을 지정해야 합니다.

# 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몇 가지 디렉터리 위치와 두 가지 사용자 지정 기능( 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 &'
}

완벽하게 제출되었으며 내 애플리케이션에는 세 가지 구성 요소가 시작되어 사용 가능한 것으로 표시됩니다.

그러나 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.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

관련 정보