프로세스 대체를 달성하기위한 이식 가능한 (POSIX) 방법은 무엇입니까?


25

과 같은 일부 쉘 은 프로세스 출력을 파일로 표시하는 방법 인 프로세스 대체bash지원 합니다.

$ diff <(sort file1) <(sort file2)

그러나이 구조는 POSIX 가 아니므로 이식성이 없습니다. 어떻게 대체가 달성 될 처리 할 수있는 POSIX 친화적 인 방식으로 (즉, 작동 하나 /bin/sh) ?

참고 :이 질문은 두 개의 정렬 된 파일을 비교하는 방법을 묻지 않습니다 . 프로세스 대체 를 보여주기 위해 고안된 예입니다 !




1
POSIX는 /bin/shPOSIX 쉘일 필요는 없으며 sh, 올바른 환경에서 POSIX를 준수하는 어딘가에 명령이 있어야 합니다. 예를 들어, Solaris 10에서 /bin/shPOSIX 쉘이 아니며 고대 Bourne 쉘이며 POSIX 쉘은에 /usr/xpg4/bin/sh있습니다.
Stéphane Chazelas

답변:


17

이 기능은 ksh(ksh86에서 처음 문서화 됨)에 의해 도입 되었으며이 /dev/fd/n기능 을 사용하고있었습니다 (일부 BSD 및 AT & T 시스템에서 독립적으로 추가됨). 에서 ksh와 ksh93u까지이 작업 시스템이 지원은 / dev / FD / N 없었다면하지 않을 것입니다. zsh, bash ksh93u+이상은 / dev / fd / n을 사용할 수없는 임시 명명 된 파이프 (SysIII에 추가 된 명명 된 파이프)를 사용할 수 있습니다.

사용 가능한 시스템 (POSIX 에서 해당 시스템을 지정하지 않음)에서 다음을 사용하여 직접 프로세스 대체 ( )를 수행 할 수 있습니다 ./dev/fd/ndiff <(cmd1) <(cmd2)

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

그러나 ksh93Linux 에서는 작동하지 않습니다 . 쉘 파이프는 파이프 대신 /dev/fd/3소켓 쌍으로 구현 되며 fd 3이 소켓을 가리키는 개구부 는 Linux에서 작동하지 않습니다.

POSIX는을 지정하지 않지만 . 명명 된 파이프를 지정합니다. 명명 된 파이프는 파일 시스템에서 해당 파이프에 액세스 할 수 있다는 점을 제외하면 일반 파이프처럼 작동합니다. 여기서 문제는 POSIX에 임시 파일이나 디렉토리를 생성하고 이식 가능한 신호 처리를 수행하는 표준 메커니즘이 없다는 점을 고려할 때 특히 임시 시스템을 생성하고 나중에 정리해야한다는 것입니다. (매달거나 죽일 때 정리하는 것)도 휴대하기가 어렵습니다./dev/fd/nmktemp -d

당신은 다음과 같은 것을 할 수 있습니다 :

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"
rm -f -- "$fifo"

(여기에서는 신호 처리를 관리하지 않음).


명명 된 파이프 예제는 나에게 완전히 분명하지만 (10은 임의의 한계라고 생각하십니까?) 귀하의 /dev/fd/n예제를 파악할 수 없습니다 . 설명자 4가 두 번 닫힌 이유는 무엇입니까? (그리고 설명자 3도 마찬가지입니다.)
와일드 카드

@Wildcard, 필요없는 명령으로 닫힙니다. 여기서 diff는 fd 3 만 필요합니다. 아무도 fd 4가 필요하지 않습니다. 원래 stdin을 cmd2( dup2(0,4)outer에서 {...}, dup2(4,0)inside 와 함께 복원)으로 전파하는 데만 사용됩니다 {...}.
Stéphane Chazelas

당신은 사용할 수 mktemp -d아무도 브랜드 - 새로운 임의의 임시 디렉토리에 작성해서는 안로서, FIFO를 얻을 수 있습니다 당신을 위해 도움이됩니다.
Daniel H

@DanielH, 나는 이미 언급했다 mktemp -d. 그러나 이것은 표준 / POSIX 명령이 아닙니다.
Stéphane Chazelas

허, 나는 그것을 몰랐다. 죄송합니다. 빠르게 검색하면 대부분의 시스템이이를 지원한다는 것을 보여 주므로 여전히 이식 가능하지만 POSIX는 아닙니다.
Daniel H

-1

유용한에서 변수 손실을 피해야하는 경우 cmd | while read A B C:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done < <(cmd)
echo "$VAR"

당신이 사용할 수있는:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done << EndOfText
`cmd`
EndOfText
echo "$VAR"

따라서 질문에 대답하려면 다음을 수행하십시오.

sort file1 | diff /dev/stdin /dev/stdout 2<<EOT
`sort file2`
EOT
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.