프로세스 대체 및 파이프

프로세스 대체 및 파이프

다음 사항을 이해하는 방법을 알고 싶습니다.

한 명령의 표준 출력을 다른 명령의 표준 입력으로 파이프하는 것은 강력한 기술입니다. 하지만 여러 명령의 표준 출력을 파이프해야 한다면 어떻게 될까요? 여기서 프로세스 대체가 시작됩니다.

즉, 파이프가 할 수 있는 일을 프로세스 교체가 할 수 있습니까?

파이프는 할 수 없지만 프로세스 대체는 무엇을 할 수 있나요?

답변1

이들 간의 차이점을 이해하는 좋은 방법은 명령줄에서 몇 가지 실험을 수행하는 것입니다. <역할의 사용은 시각적으로 유사 하지만 리디렉션이나 파이프와는 매우 다르게 작동합니다.

date테스트를 위해 명령을 사용합니다 .

$ date | cat
Thu Jul 21 12:39:18 EEST 2011

이것은 무의미한 예이지만 catSTDIN에서 출력을 가져 date와서 뱉어내는 것을 보여줍니다. 절차적 대체를 사용해도 동일한 결과를 얻을 수 있습니다.

$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011

그러나 뒤에서 일어나는 일은 다릅니다. cat실제로 전달되는 것은 STDIN 스트림을 제공하는 것이 아니라 열고 읽는 데 필요한 파일 이름입니다. 대신 를 사용하여 echo이 단계를 볼 수 있습니다 cat.

$ echo <(date)
/proc/self/fd/11

cat이 파일 이름을 받으면 파일 내용을 읽어줍니다. 반면에 Echo는 전달된 파일 이름만 보여줍니다. 대체 항목을 더 추가하면 이 차이는 더욱 두드러집니다.

$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011

$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13

프로세스 교체(파일 생성)와 입력 리디렉션(파일을 STDIN에 연결)을 결합할 수 있습니다.

$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011

거의 동일해 보이지만 이번에는 cat에 파일 이름 대신 STDIN 스트림이 전달됩니다. echo를 사용하여 이를 확인할 수 있습니다.

$ echo < <(date)
<blank>

echo는 STDIN을 읽지 않고 매개변수도 전달되지 않으므로 아무것도 얻지 못합니다.

파이프 및 입력 리디렉션은 콘텐츠를 STDIN 스트림으로 푸시합니다. 프로세스 대체는 명령을 실행하고 해당 출력을 특수 임시 파일에 저장한 다음 명령 대신 해당 파일 이름을 전달합니다. 어떤 명령을 사용하든 이를 파일 이름으로 처리합니다. 생성된 파일은 일반 파일이 아니라 명명된 파이프이며 더 이상 필요하지 않으면 자동으로 삭제됩니다.

답변2

다음은 프로세스 대체를 통해 달성할 수 있는 세 가지 사항입니다.

다중 프로세스 입력

diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)

파이프로는 이 작업을 수행할 수 있는 방법이 없습니다.

표준 입력 유지

다음이 있다고 가정해 보겠습니다.

curl -o - http://example.com/script.sh
   #/bin/bash
   read LINE
   echo "You said ${LINE}!"

그리고 직접 실행하고 싶습니다. 다음은 비참하게 실패했습니다. Bash는 이미 STDIN을 사용하여 스크립트를 읽기 때문에 다른 입력은 불가능합니다.

curl -o - http://example.com/script.sh | bash 

그러나 이것은 잘 작동합니다.

bash <(curl -o - http://example.com/script.sh)

아웃바운드 프로세스 교체

또한 프로세스 대체는 다른 방식으로도 작동합니다. 그래서 당신은 이것을 할 수 있습니다 :

(ls /proc/*/exe >/dev/null) 2> >(sed -n \
  '/Permission denied/ s/.*\(\/proc.*\):.*/\1/p' > denied.txt )

이것은 약간 복잡한 예이지만 다음과 같이 전송됩니다.표준 출력/dev/null동시에 파이프라인표준 에러sed 스크립트로 "권한 거부" 오류를 표시하는 파일 이름을 추출한 다음 해당 결과를 파일로 보냅니다.

첫 번째 명령과표준 출력리디렉션은 대괄호(서브쉘) 해당 명령의 결과만 전송되고 /dev/null나머지 줄을 방해하지 않도록 합니다.

답변3

bash나는 posix 쉘이 없기 때문에 당신이 또는 다른 고급 쉘에 대해 이야기하고 있다고 가정해야 합니다.프로세스 교체.

bash매뉴얼 페이지는 다음을 보고합니다:

프로세스 교체
프로세스 대체는 명명된 파이프(FIFO) 또는 /dev/fd 명명된 파일 열기 방법을 지원하는 시스템에서 지원됩니다. <(목록) 또는 >(목록) 형식을 사용합니다. 프로세스 목록의 입력 또는 출력은 FIFO 또는 /dev/fd의 파일에 연결됩니다. 파일 이름은 확장 결과로 현재 명령에 인수로 전달됩니다. >(목록) 형식을 사용하는 경우 파일에 쓰면 목록에 대한 입력이 제공됩니다. <(목록) 형식을 사용하는 경우 목록의 출력을 얻으려면 인수로 전달된 파일을 읽어야 합니다.

가능한 경우 프로세스 대체는 매개변수 및 변수 확장, 명령 대체 및 산술 확장과 동시에 수행됩니다.

즉, 실용적인 관점에서 보면 다음과 같은 표현을 사용할 수 있습니다.

<(commands)

파일을 인수로 요구하는 다른 명령의 파일 이름. 또는 다음과 같이 파일에 대한 리디렉션을 사용할 수 있습니다.

while read line; do something; done < <(commands)

귀하의 질문으로 돌아가서 프로세스 대체와 파이프에는 공통점이 많지 않은 것 같습니다.

여러 명령의 출력을 순차적으로 파이프하려면 다음 형식 중 하나를 사용할 수 있습니다.

(command1; command2) | command3
{ command1; command2; } | command3

그러나 프로세스 교체 시 리디렉션을 사용할 수도 있습니다.

command3 < <(command1; command2)

마지막으로 command3(stdin 대신) 파일 인수를 수락 하면

command3 <(command1; command2)

답변4

<(command)프로세스 교체는 양식에만 국한되지 않고 출력을 command파일로 사용한다는 점에 유의해야 합니다 . >(command)파일을 입력으로 사용하는 형식을 취할 수도 있습니다 . command@enzotib의 답변에 인용된 bash 매뉴얼에서도 이에 대해 언급되어 있습니다.

date | cat위의 예 에서 >(command)형식의 프로세스 대체를 사용하여 동일한 효과를 얻는 명령은 다음과 같습니다.

date > >(cat)

>앞의 내용이 >(cat)필수 이므로 주의하시기 바랍니다 . echo@Caleb의 답변은 이것을 다시 명확하게 만듭니다.

$ echo >(cat)
/dev/fd/63

따라서 extras가 없으면 >stderr에 메시지를 인쇄하는 것과 같습니다 date >(cat).date /dev/fd/63

stdin파일 이름만 인수로 취하고 또는 는 처리하지 않는 프로그램이 있다고 가정합니다 stdout. psub.sh이를 설명하기 위해 지나치게 단순화된 스크립트를 사용하겠습니다 . 내용 psub.sh

#!/bin/bash
[ -e "$1" ] && [ -e "$2" ] && awk '{print $1}' < "$1" > "$2"

기본적으로 두 인수가 모두 파일(일반 파일일 필요는 없음)인지 테스트하고, 그렇다면 awk를 사용하여 각 줄의 첫 번째 필드 "$1""$2". 그러면 지금까지 언급한 모든 명령을 결합한 명령은 다음과 같습니다.

./psub.sh <(printf "a a\nc c\nb b") >(sort)

이것은 인쇄됩니다

a
b
c

그리고 동등하다

printf "a a\nc c\nb b" | awk '{print $1}' | sort

하지만 아래 방법은 작동하지 않습니다. 여기서는 프로세스 대체를 사용해야 합니다.

printf "a a\nc c\nb b" | ./psub.sh | sort

또는 그에 상응하는 것

printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort

위에서 언급한 것 외에 ./psub.sh읽을 수 있는 stdin경우 해당 항목은 존재하지 않으며 이 경우 프로세스 교체 대신 아무것도 사용할 수 없습니다(물론 명명된 파이프나 임시 파일을 사용할 수도 있지만 이는 또 다른 이야기입니다) ).

관련 정보