대시: STDIN을 여러 명령에 파이프하고 해당 출력을 정의된 순서에 따라 STDOUT에 파이프합니다.

대시: STDIN을 여러 명령에 파이프하고 해당 출력을 정의된 순서에 따라 STDOUT에 파이프합니다.

처음에 나는 생각했다이 답변해결책이 있는데 지금은 버퍼로 사용할 임시 파일이 필요한 것 같습니다.

이것은 신뢰할 수 없게 작동합니다.

#!/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명 이상의 소비자에서는 작동할 수 없습니다.poshksh93

답변2

최고의 솔루션임시 파일을 사용하십시오. 이를 통해 프로세스 교체가 불가능할 때 코드를 읽기 쉽고 이해하기 쉽게 만듭니다.

tmpfile=$(mktemp)

producer | tee "$tmpfile" | consumer1
consumer2 <"$tmpfile"

rm -f "$tmpfile"

심지어

tmpfile=$(mktemp)

producer >"$tmpfile"

consumer1 <"$tmpfile"
consumer2 <"$tmpfile"

rm -f "$tmpfile"

관련 정보