Bash 스크립트는 프로세스를 기다리고 리턴 코드를 얻습니다.


13

많은 백그라운드 명령을 시작하는 스크립트를 만들려고합니다. 각 백그라운드 명령마다 반환 코드를 가져와야합니다.

나는 다음 스크립트를 시도했다 :

 #!/bin/bash
set -x
pid=()
return=()


for i in 1 2
do
 echo start $i
 ssh mysql "/root/test$i.sh" &
 pid[$i]=$!
done

for i in ${#pid[@]}
do
echo ${pid[$i]}
wait ${pid[$i]}
return[$i]=$?

if [ ${return[$i]} -ne 0 ]
then
  echo mail error
fi

done

echo ${return[1]}
echo ${return[2]}

내 문제는 대기 루프 중입니다. 첫 번째 문제 전에 두 번째 pid가 완료되면 반환 코드를 얻을 수 없습니다.

wait pid1 pid2를 실행할 수 있다는 것을 알고 있지만이 명령으로 모든 명령의 리턴 코드를 얻을 수는 없습니다.

어떤 아이디어?

답변:


6

임시 디렉토리를 사용하여이를 수행 할 수 있습니다.

# Create a temporary directory to store the statuses
dir=$(mktemp -d)

# Execute the backgrouded code. Create a file that contains the exit status.
# The filename is the PID of this group's subshell.
for i in 1 2; do
    { ssh mysql "/root/test$i.sh" ; echo "$?" > "$dir/$BASHPID" ; } &
done

# Wait for all jobs to complete
wait

# Get return information for each pid
for file in "$dir"/*; do
    printf 'PID %d returned %d\n' "${file##*/}" "$(<"$file")"
done

# Remove the temporary directory
rm -r "$dir"

9

문제는 더

for i in ${#pid[@]}

어느 것입니다 for i in 2.

오히려 다음과 같아야합니다.

for i in 1 2

또는

for ((i = 1; i <= ${#pid[@]}; i++))

wait "$pid" 와 작업의 종료 코드 반환 bash(및 POSIX 쉘을,하지만 zsh때 작업이 이미 종료 한 경우에도) wait시작되었습니다.


5

임시 파일이없는 일반적인 구현입니다.

#!/usr/bin/env bash

## associative array for job status
declare -A JOBS

## run command in the background
background() {
  eval $1 & JOBS[$!]="$1"
}

## check exit status of each job
## preserve exit status in ${JOBS}
## returns 1 if any job failed
reap() {
  local cmd
  local status=0
  for pid in ${!JOBS[@]}; do
    cmd=${JOBS[${pid}]}
    wait ${pid} ; JOBS[${pid}]=$?
    if [[ ${JOBS[${pid}]} -ne 0 ]]; then
      status=${JOBS[${pid}]}
      echo -e "[${pid}] Exited with status: ${status}\n${cmd}"
    fi
  done
  return ${status}
}

background 'sleep 1 ; false'
background 'sleep 3 ; true'
background 'sleep 2 ; exit 5'
background 'sleep 5 ; true'

reap || echo "Ooops! Some jobs failed"

감사합니다 :-) 이것은 내가 찾던 것입니다!
Qorbani

0

스테판의 대답은 좋지만 선호합니다.

for i in ${!pid[@]}
do
    wait ${pid[i]}
    return[i]=$?
    unset "pid[$i]"
done

어떤 pid항목이 여전히 존재하는지에 관계없이 배열 의 키를 반복 하므로 해당 항목을 조정하고 루프를 벗어나 전체 루프를 다시 시작하면 작동합니다. 그리고 i시작하기 위해 연속적인 값이 필요하지 않습니다 .

물론 수천 개의 프로세스를 처리하는 경우 스파 스가 아닌 목록이 있으면 스테판의 접근 방식이 훨씬 효율적일 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.