명명된 파이프를 사용하여 프로세스 교체 종료 코드 가져오기

명명된 파이프를 사용하여 프로세스 교체 종료 코드 가져오기

여러 프로세스 대체가 포함된 상당히 복잡한 명령이 포함된 스크립트가 있는데, 프로세스 대체 내의 명령에서 종료 코드를 가져와야 합니다. 명명된 파이프를 통해 이 작업을 수행하려고 하는데 이전에 명명된 파이프를 사용한 적이 없기 때문에 문제가 있습니다.

예를 들어, 다음 명령이 주어지면:

somecommand <(someothercommand; echo $? > named_pipe) <(someothercommand; echo $? > named_pipe) &

somecommand완료될 때까지 기다리고 모든 종료 코드를 읽는 올바른 방법은 무엇입니까 named_pipe(실제로 얼마나 많은 종료 코드가 작성될지 모른다고 가정 named_pipe)? 지금까지의 시도는 차단 somecommand(에서 무언가를 읽기를 기다리고 있다고 가정하기 때문에 named_pipe)되거나 종료 코드만 읽는 결과를 가져왔습니다.

답변1

사실 이는 그리 간단해 보이지는 않습니다. 쉘이 프로세스 교체 대기를 지원한다면 가장 좋을 수도 있지만 Bash는 그렇게 하지 않을 것 같습니다.

또 다른 문제는 명명된 파이프가 거기에 쓰고 싶은 줄 수를 알 수 없다는 것입니다. 모든 작성기가 닫히면 파이프는 EOF를 읽지만 모든 쓰기에서 EOF를 얻을 수 있습니다 echo. 동시에 공격하지 않는 한, 그런 경우에는 그렇지 않습니다.

그러나 처음부터 쓰기 fd를 열도록 프로세스 교체를 예약하여 모든 작업이 완료된 후 EOF가 한 번만 발생하도록 하는 것이 가능해 보입니다.

이와 같이 echo somecommand및 를 사용하여 실제 명령을 true나타냅니다 .false

#!/bin/bash

dir=$(mktemp -d)
p="$dir/p"
mkfifo "$p"

# whole subshell sent to the background
(exec 3> "$p"; 
 # both process substitutions get a copy of fd 3
 echo somecommand \
    <(false; echo "cmd1: $?" >&3) \
    <(true;  echo "cmd2: $?" >&3) \

) &

# read the exit statuses, this will see EOF once all the three
# background processes above finish
cat "$p"
rm -rf "$dir" 2>/dev/null

파이프에 인쇄되는 라인의 순서는 시간에 따라 다르며 본질적으로 무작위입니다.

echo somecommand또한 느리게 실행되는 경우 먼저 나오는 출력을 얻을 수 있습니다 . cat "$p"파이프에서 변수로 데이터를 읽어온 다음 wait이를 백그라운드 프로세스에서 사용해야 합니다.

context 없이도 가능 somecommand하지만 파일 핸들을 사용하려면 더 많은 연습이 필요합니다.

#!/bin/bash

dir=$(mktemp -d)
p="$dir/p"
mkfifo "$p"

# open an fd for read+write (doesn't block because both open)
exec 3<>"$p"

# process substs inherit the fd, closing it when they exit
echo somecommand \
    <(false; echo "cmd1: $?" >&3) \
    <(true;  echo "cmd2: $?" >&3) \

# open another reader to keep the pipe live
exec 4<"$p"

# now we can close the writing handle
exec 3>&-

# read the data off
cat <&4
exec 4<&-

rm -rf "$dir" 2>/dev/null

종료 상태를 일반 파일로 수집하고 알려진 행 수까지 읽는 것이 더 간단할 수 있습니다.

#!/bin/bash

f=$(mktemp)

# number of process substitutions
n=2
echo somecommand \
    <(false; echo "cmd1: $?" >>"$f") \
    <(true;  echo "cmd2: $?" >>"$f") \

exec 3< "$f"
# read that many lines
for ((i = 0; i < n; i++)) do
    # if the data isn't there yet, retry reading until a new line appears
    until read line <&3; do sleep 1; done
    echo "$line";
done 
exec 3<&-

rm -f "$f"

테스트한 바에 따르면 세 가지 모두 작동하는 것 같지만 프로세스 대체 및 파이프를 사용하는 것은 번거로울 수 있으므로 일부 실패 모드가 누락될 수 있습니다.

관련 정보