프로세스 대체 및 파이프

다음을 이해하는 방법이 궁금합니다.

명령의 stdout을 다른 명령의 stdin으로 파이핑하는 것은 강력한 기술입니다. 그러나 여러 명령의 표준 출력을 파이프해야하는 경우 어떻게해야합니까? 여기서 프로세스 대체가 시작됩니다.

즉, 프로세스 대체가 파이프가 할 수있는 모든 작업을 수행 할 수 있습니까?

프로세스 대체는 무엇을 할 수 있지만 파이프는 할 수 없습니까?

답변

그들 사이의 차이점은 명령 줄에서 약간의 실험을하는 것입니다. < 문자를 사용하는 시각적 유사성에도 불구하고 리디렉션이나 파이프와는 매우 다른 작업을 수행합니다.

명령을 테스트합니다.

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

이것은 무의미한 예이지만 cat는 STDIN에서 date의 출력을 수락하고 다시 뱉어냅니다. 프로세스 대체로 동일한 결과를 얻을 수 있습니다.

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

하지만 막 뒤에서 일어난 일은 달랐습니다. STDIN 스트림이 제공되는 대신 cat에 실제로 열어야하는 파일 이름이 전달되었습니다. 이 단계는 cat 대신 echo를 사용하여 볼 수 있습니다.

$ 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 

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

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

거의 비슷해 보이지만 이번에는 cat이 파일 이름 대신 STDIN 스트림을 전달 받았습니다. echo로 시도하면 확인할 수 있습니다.

$ echo < <(date) <blank> 

echo는 STDIN을 읽지 않으므로 인수가 전달되지 않으면 아무것도 얻지 못합니다.

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

댓글

  • 정확하게 이해하면 tldp.org/LDP/abs/html/process-sub.html#FTN.AEN18244 는 프로세스 대체가 명명 된 파이프가 아닌 임시 파일을 생성한다고 말합니다. 내가 아는 한 임시 파일을 만들지 마십시오. 파이프에 쓰기에는 디스크에 쓰기가 포함되지 않습니다. stackoverflow.com/a/6977599/788700
  • 이 답변이 합법적이라는 것을 알고 있습니다. ‘ grok : D
  • @Adobe라는 단어를 사용하므로 임시 파일 프로세스 대체가 생성하는 이름이 다음과 같은 파이프인지 확인할 수 있습니다. [[ -p <(date) ]] && echo true. bash 4.4 또는 3.2로 실행할 때 true가 생성됩니다.

Answer

다른 방법으로는 불가능한 프로세스 대체로 수행 할 수있는 세 가지 작업이 있습니다.

다중 프로세스 입력

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

저기 단순히 파이프로이를 수행하는 방법이 아닙니다.

STDIN 보존

다음이 있다고 가정 해보십시오.

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 ) 

이것은 약간 복잡한 예제이지만 stdout

, stderr 을 sed 스크립트로 파이핑하여 ” 권한이 거부 된 파일의 이름을 추출합니다. ” 오류가 표시된 다음 THOSE 결과를 파일로 보냅니다.

첫 번째 명령과 stdout 리디렉션은 괄호 안에 있습니다. ( 서브 셸 ) 해당 명령의 결과 만 /dev/null로 전송되고 나머지 줄이 엉망이되지 않도록합니다.

댓글

  • ‘는 diff에서 주목할 가치가 있습니다. 예를 들어 cd가 실패 할 수있는 경우에 관심을 가질 수 있습니다. diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls).
  • ” 표준 파이프를 배관하는 동안 ” : ‘ 이것이 파이핑이 아니고 fifo 파일을 통과한다는 것을 지적합니까?
  • @Gauthier no; 명령은 fifo가 아니라 파일 설명자에 대한 참조로 대체됩니다. 따라서 ” echo < (echo) “는 ” / dev / fd / 63 “는 FD 번호 63에서 읽거나 쓰는 특수 문자 장치입니다.

답변

bash 또는 기타 고급 셸에 대해 이야기하고 있다고 가정해야합니다. 쉘에는 프로세스 대체 가 없습니다.

bash 매뉴얼 페이지 보고서 :

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

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

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

<(commands) 

파일이 매개 변수로 필요한 다른 명령의 파일 이름입니다. 또는 이러한 파일에 대해 리디렉션을 사용할 수 있습니다.

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

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

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

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

하지만 프로세스 대체시 리디렉션을 사용할 수도 있습니다.

command3 < <(command1; command2) 

마지막으로 command3가 파일 매개 변수를 허용하는 경우 (표준 입력 대신 )

command3 <(command1; command2) 

댓글

  • < ( ) 및 < < ()는 동일한 효과를냅니다.
  • @solfish : 정확하지 않습니다. 파일 이름이 예상되는 곳이면 어디에서나 두 번째는 해당 파일 이름에 대한 입력 리디렉션입니다.

Answer

명령은 파일 목록을 인수로 취하고 해당 파일을 입력으로 처리합니다 (또는 일반적으로 출력되지는 않지만 각 파일은 프로세스 대체에 의해 투명하게 제공되는 명명 된 파이프 또는 / dev / fd 의사 파일 일 수 있습니다.

$ sort -m <(command1) <(command2) <(command3) 

정렬은 명령 줄에서 입력 파일 목록을 가져올 수 있으므로 정렬 할 세 명령의 출력을 “파이프”합니다.

댓글

  • IIRC < (명령) 구문은 bash 전용 기능입니다.
  • @Philomath : It ‘ s ZSH도 마찬가지입니다.
  • 음, ZSH는 모든 것을 갖추고 있습니다 … (또는 최소한 시도)
  • @Philomath : 프로세스 대체는 다른 쉘에서 어떻게 구현됩니까?
  • @Philomath <()는 많은 고급 셸 기능과 마찬가지로 원래 ksh 기능이었으며 bash 및 zsh에서 채택되었습니다. psub는 특히 물고기 기능이며 POSIX와는 관련이 없습니다.

답변

프로세스 대체는 command의 출력을 사용하는 <(command) 형식으로 제한되지 않습니다. 파일. 파일을 command에 대한 입력으로 공급하는 >(command) 형식 일 수도 있습니다. 이것은 @enzotib “의 대답에있는 bash 매뉴얼의 인용문에서도 언급됩니다.

위의 date | cat 예제의 경우 프로세스 대체를 사용하는 명령 양식 >(command)는 동일한 효과를 얻을 수 있습니다.

date > >(cat) 

> 전에 >(cat)가 필요합니다. 이는 @Caleb의 답변에서와 같이 echo로 다시 명확하게 설명 할 수 있습니다.

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

따라서 추가 > 없이는 date >(cat)가 stderr에 메시지를 인쇄하는 date /dev/fd/63와 동일합니다.

파일 이름 만 매개 변수로 사용하고 또는 stdout.이를 설명하기 위해 지나치게 단순화 된 스크립트 psub.sh를 사용하겠습니다. psub.sh의 내용은

#!/bin/bash [ -e "$1" -a -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 위에 언급 된 것 외에는 그러한 동등한 형식이 존재하지 않으며,이 경우 프로세스 대체 대신 사용할 수있는 것이 없습니다 (물론 이름이 지정된 파이프 또는 임시 파일이지만 이는 또 다른 이야기입니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다