Tập lệnh Bash chờ xử lý và nhận mã trả về


13

Tôi đang cố gắng tạo một kịch bản sẽ bắt đầu nhiều lệnh nền. Đối với mỗi lệnh nền tôi cần lấy mã trả về.

Tôi đã thử đoạn script sau:

 #!/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]}

Vấn đề của tôi là trong vòng chờ, nếu lần thứ hai kết thúc trước lần thứ nhất, tôi sẽ không thể lấy được mã trả về.

Tôi biết rằng tôi có thể chạy Wait pid1 pid2, nhưng với lệnh này, tôi không thể nhận được mã trả về của tất cả các lệnh.

Bất kỳ ý tưởng ?

Câu trả lời:


6

Bạn có thể làm điều này bằng cách sử dụng một thư mục tạm thời.

# 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

Vấn đề là nhiều hơn với bạn

for i in ${#pid[@]}

Đó là for i in 2.

Nó nên là:

for i in 1 2

hoặc là

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

wait "$pid" sẽ trả về mã thoát của công việc bằng bash(và shell POSIX, nhưng không zsh) ngay cả khi công việc đã kết thúc khi waitbắt đầu.


5

Một thực hiện chung mà không có tập tin tạm thời.

#!/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"

Cảm ơn bạn :-) Đây chính xác là những gì tôi đang tìm kiếm!
Qorbani

0

Câu trả lời của Stéphane là tốt, nhưng tôi thích

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

sẽ lặp lại các khóa của pidmảng, bất kể mục nào vẫn tồn tại, do đó bạn có thể điều chỉnh nó, thoát ra khỏi vòng lặp và khởi động lại toàn bộ vòng lặp và nó sẽ chỉ hoạt động. Và bạn không cần các giá trị liên tiếp củai để bắt đầu.

Tất nhiên, nếu bạn đang xử lý hàng ngàn quy trình thì có lẽ cách tiếp cận của Stépane sẽ hiệu quả hơn một chút khi bạn có một danh sách không thưa thớt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.