프로세스 교체를 구현하는 이식 가능한(POSIX) 방법은 무엇입니까?

프로세스 교체를 구현하는 이식 가능한(POSIX) 방법은 무엇입니까?

예를 들어 일부 쉘은 bash다음을 지원합니다.프로세스 교체이는 다음과 같이 프로세스의 출력을 파일로 렌더링하는 방법입니다.

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

그러나 이 구성은 그렇지 않습니다.POSIX그러므로 휴대가 쉽지 않습니다.프로세스 대체를 달성하는 방법POSIX- 친절한 태도(즉, 에서 일함 /bin/sh)?

참고: 질문은 두 개의 정렬된 파일을 구별하는 방법을 묻는 것이 아닙니다. 이것은 단지 설명하기 위해 고안된 예일 뿐입니다.프로세스 교체!

답변1

이 기능은 ksh도입되었으며(ksh86에 처음 문서화됨) 사용 중입니다(이전에 일부 BSD 및 AT&T 시스템에 독립적으로 추가됨). ksh93u 및 이전 버전에서는 시스템이 지원하지 않는 한 zsh, bash 이상에서는 사용할 수 없는 경우 임시 명명된 파이프(System III에 추가된 명명된 파이프)를 사용할 수 있습니다./dev/fd/nksh/dev/fd/nksh93u+/dev/fd/n

사용 가능한 시스템(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

ksh93그러나 쉘 파이프는 파이프가 아닌 소켓 쌍으로 구현되고 /dev/fd/3소켓 위치를 가리키는 fd 3을 여는 것이 Linux에서 작동하지 않기 때문에 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"

cleanup

(여기서는 신호 처리를 고려하지 않습니다.)

답변2

이를 달성하려면 heredoc 및 /dev/fd/n 파일을 사용할 수 있습니다. 예를 들어 bash다음과 같이 할 수 있습니다.

#!/usr/bin/env bash

paste  <(echo "$SHELL") <(echo "$TERM") <(echo "$LANG")

하지만 POSIX sh에서는 다음을 수행해야 합니다.

#!/bin/sh

paste /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF /dev/fd/5 5<<-EOF 
$SHELL
EOF
$TERM
EOF
$LANG
EOF

출력은 동일합니다.

질문에 대답하려면 다음과 같이 작동합니다.

#!/bin/sh

diff /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF
$(sort file1)
EOF
$(sort file2)
EOF

투박해 보이지만 작동합니다.

답변3

유용한 변수를 잃지 않으려면 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

관련 정보