공정 대체 및 파이프


86

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

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

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

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

답변:


133

그들 사이의 차이점을 알아내는 좋은 방법은 커맨드 라인에서 약간의 실험을하는 것입니다. <캐릭터 의 시각적 유사성에도 불구하고 리디렉션이나 파이프와는 매우 다른 일을합니다.

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

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

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

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

그러나 막 뒤에서 일어난 일은 달랐습니다. STDIN 스트림을받는 대신 cat실제로 열어서 읽어야하는 파일 이름이 전달되었습니다. 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 스트림으로 전달합니다. 프로세스 대체는 명령을 실행하고 출력을 특수 임시 파일에 저장 한 다음 명령 대신 해당 파일 이름을 전달합니다. 어떤 명령을 사용하든 파일 이름으로 취급합니다. 작성된 파일은 일반 파일이 아니라 더 이상 필요하지 않으면 자동으로 제거되는 명명 된 파이프입니다.


corretly 이해하면 tldp.org/LDP/abs/html/process-sub.html#FTN.AEN18244에 따르면 프로세스 대체는 파이프라는 이름이 아닌 임시 파일을 만듭니다. 내가 아는 한 임시 파일을 만들지 마십시오. 파이프에 쓰기는 디스크에 쓰기를 포함하지 않습니다. stackoverflow.com/a/6977599/788700
Adobe

나는 grok : D
aqn

2
@Adobe는 임시 파일 프로세스 대체가 생성하는 명명 된 파이프인지 여부를 확인할 수 있습니다 [[ -p <(date) ]] && echo true. 이것은 truebash 4.4 또는 3.2로 실행할 때 생성 됩니다.
드 노보

24

bashposix 쉘에는 프로세스 대체 가 없기 때문에 다른 고급 쉘 에 대해 이야기하고 있다고 가정해야합니다 .

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파일 매개 변수를 수락하면 (stdin 대신)

command3 <(command1; command2)

그래서 <()와 <<()도 같은 효과를냅니다.
solfish

@solfish : exacllty가 아님 : 파일 이름이 필요한 곳마다 firse를 사용할 수 있고, 두 번째는 해당 파일 이름의 입력 경로 재 지정
enzotib

23

그렇지 않으면 불가능한 프로세스 대체로 수행 할 수있는 세 가지 작업이 있습니다.

여러 프로세스 입력

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 스크립트로 /dev/null파이프 하여 "Permission denied"오류가 표시된 파일의 이름을 추출한 다음 THOSE 결과를 파일로 보냅니다.

첫 번째 명령과 stdout 리디렉션은 괄호 ( subshell )로되어 있으므로 THAT 명령의 결과 만 전송되고 /dev/null나머지 행은 엉망이되지 않습니다.


diff예에서는 cd실패한 경우에 대해 관심을 가질 수 있습니다 diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls).
phk

"열려진 배관하면서"이 있다는 점하지 아니 배관하지만, FIFO 파일을 통해 갈은?
Gauthier

@Gauthier 아니오; 이 명령은 fifo가 아니라 파일 디스크립터에 대한 참조로 대체됩니다. 따라서 "echo <(echo)"는 "/ dev / fd / 63"과 같이 FD 번호 63에서 읽거나 쓰는 특수 문자 장치입니다.
tylerl

10

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

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

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


1
IIRC <(명령) 구문은 bash 전용 기능입니다.
Philomath

@ Philomath : ZSH에도 있습니다.
Caleb

글쎄, ZSH는 모든 것을 가지고 있습니다 (또는 적어도 시도합니다).
Philomath

@ Philomath : 다른 쉘에서 프로세스 대체는 어떻게 구현됩니까?
camh

4
@Philomath <()는 많은 고급 쉘 기능과 마찬가지로 원래 ksh 기능이며 bash 및 zsh에 의해 채택되었습니다. psubPOSIX와 관련이없는 물고기 기능입니다.
Gilles

3

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

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

date > >(cat)

점을 유의 >전에이 >(cat)필요하다. 이것은 echo@Caleb의 답변에서와 같이 다시 명확하게 설명 될 수 있습니다 .

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

그래서, 추가하지 않고 >, date >(cat)같은 것 date /dev/fd/63stderr에 메시지를 인쇄 할 수있다.

당신은 단지 매개 변수로 파일 이름을 소요하고 처리하지 않는 프로그램이 가정 stdin또는 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에는 이와 동등한 형식이 존재하지 않으며,이 경우 프로세스 대체 대신 사용할 수있는 것이 없습니다 (물론 명명 된 파이프 또는 임시 파일을 사용할 수도 있지만 이는 또 다른 것입니다) 이야기).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.