처음에 나는 생각했다이 답변해결책이 있는데 지금은 버퍼로 사용할 임시 파일이 필요한 것 같습니다.
이것은 신뢰할 수 없게 작동합니다.
#!/bin/sh
echo 'OK' |
{
{
tee /dev/fd/3 | head --bytes=1 >&4
} 3>&1 | tail --bytes=+2 >&4
} 4>&1
터미널에서 이것을 실행하면 때때로 다음과 같은 결과가 나타납니다.
좋아요
때때로 나는 다음을 얻습니다:
칼륨
완전히 무작위로 보입니다. 그래서 해결 방법으로 출력을 파일에 기록하고 파이프라인이 완료된 후 tail
다시 읽습니다 .stdout
#!/bin/sh
echo 'OK' |
{
{
tee /dev/fd/3 | head --bytes=1 >&4
} 3>&1 | tail --bytes=+2 >file
} 4>&1
cat file
dash
임시 파일 없이 이 작업을 수행할 수 있습니까? 출력에 NUL 바이트가 포함될 수 있으므로 버퍼로서의 쉘 변수도 옵션이 아닙니다.
답변1
소비자와 생산자를 병렬로 실행하지만 소비자의 출력을 직렬화하려는 경우 두 번째 소비자의 출력을 지연해야 합니다. 이렇게 하려면 출력을 어떻게든 저장해야 합니다. 가장 좋은 방법은 임시 파일을 사용하는 것입니다.
그리고 zsh
:
{cat =(producer > >(consumer1 >&3) | consumer2)} 3>&1
bash
프로세스 교체 명령을 기다리지 않기 때문에 문제가 있으므로 거기에 대한 불쾌한 해결 방법을 사용해야 합니다..
여기서는 =(...)
프로세스 대체 형식을 사용하여 출력을 저장하기 전에 comsumer2
임시 파일에 저장합니다 cat
. 2명 이상의 소비자에 대해서는 이 작업을 수행할 수 없습니다. 이렇게 하려면 임시 파일을 수동으로 만들어야 합니다.
사용하지 않을 때는 =(...)
임시 파일을 수동으로 정리해야 합니다 . 이를 미리 생성하고 삭제하여 처리할 수 있으므로 스크립트가 종료되는 것에 대해 걱정할 필요가 없습니다. 아직 있습니다 zsh
:
tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
rm -f -- $tmp1 $tmp2
producer > >(consumer1) > >(consumer2 >&3) > >(consumer3 >&5)
cat <&4 <&6
} 3> $tmp1 4< $tmp1 5> $tmp2 6< $tmp2
dash
편집(처음에는 솔루션이 필요하다는 사실을 놓쳤습니다)
dash
(또는 2 이상의 fds에 close-on-exec 플래그를 설정하지 않고 소켓 쌍 대신 파이프를 사용하는 POSIX 쉘 |
) 및 지원되는 시스템의 경우 /dev/fd/x
:
tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
rm -f -- "$tmp1" "$tmp2"
{
{
{
producer | tee /dev/fd/4 /dev/fd/6 | consumer1 >&7
} 4>&1 | consumer2 >&3
} 6>&1 | consumer3 >&5
} 7>&1
cat - /dev/fd/6 <&4
} 3> "$tmp1" 4< "$tmp1" 5> "$tmp2" 6< "$tmp2"
Linux에서는 dash
, bash
, zsh
, mksh
, 에서는 작동 busybox sh
하지만 에서는 작동하지 않습니다. 이 접근 방식은 fds 0~9로 제한되므로 4명 이상의 소비자에서는 작동할 수 없습니다.posh
ksh93
답변2
최고의 솔루션예임시 파일을 사용하십시오. 이를 통해 프로세스 교체가 불가능할 때 코드를 읽기 쉽고 이해하기 쉽게 만듭니다.
tmpfile=$(mktemp)
producer | tee "$tmpfile" | consumer1
consumer2 <"$tmpfile"
rm -f "$tmpfile"
심지어
tmpfile=$(mktemp)
producer >"$tmpfile"
consumer1 <"$tmpfile"
consumer2 <"$tmpfile"
rm -f "$tmpfile"