다음을 이해하는 방법이 궁금합니다.
명령의 표준 출력을 다른 표준의 표준 입력으로 파이프하는 것은 강력한 기술입니다. 그러나 여러 명령의 표준을 파이프해야하는 경우 어떻게해야합니까? 여기에서 프로세스 대체가 시작됩니다.
다시 말해, 프로세스 대체가 파이프가 할 수있는 모든 작업을 수행 할 수 있습니까?
대체 프로세스는 무엇을 할 수 있지만 파이프는 할 수 없습니까?
답변
그들 사이의 차이점을 알아내는 좋은 방법은 커맨드 라인에서 약간의 실험을하는 것입니다. <
캐릭터 의 시각적 유사성에도 불구하고 리디렉션이나 파이프와는 매우 다른 일을합니다.
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 스트림으로 전달합니다. 프로세스 대체는 명령을 실행하고 출력을 특수 임시 파일에 저장 한 다음 명령 대신 해당 파일 이름을 전달합니다. 어떤 명령을 사용하든 파일 이름으로 취급합니다. 작성된 파일은 일반 파일이 아니라 더 이상 필요하지 않으면 자동으로 제거되는 명명 된 파이프입니다.
답변
bash
posix 쉘에는 프로세스 대체 가 없기 때문에 다른 고급 쉘 에 대해 이야기하고 있다고 가정해야합니다 .
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)
답변
그렇지 않으면 불가능한 프로세스 대체로 수행 할 수있는 세 가지 작업이 있습니다.
여러 프로세스 입력
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
나머지 행은 엉망이되지 않습니다.
답변
명령이 파일 목록을 인수로 사용하여 해당 파일을 입력 (또는 출력은 아니지만 일반적으로 출력)으로 처리하는 경우 해당 파일 각각은 프로세스 대체에 의해 투명하게 제공되는 명명 된 파이프 또는 / dev / fd 의사 파일 일 수 있습니다.
$ sort -m <(command1) <(command2) <(command3)
sort는 명령 줄에서 입력 파일 목록을 가져올 수 있으므로 정렬 할 세 명령의 출력을 “파이프”합니다.
답변
프로세스 대체는 형식으로 제한되지 않으며 파일 <(command)
의 출력을 사용 command
합니다. >(command)
파일을 입력으로 공급하는 형식 일 수도 있습니다 command
. 이것은 @enzotib의 답변에서 bash 매뉴얼을 인용 할 때도 언급됩니다.
date | cat
위 의 예에서 양식의 프로세스 대체를 사용 >(command)
하여 동일한 효과를 달성 하는 명령은 다음과 같습니다.
date > >(cat)
점을 유의 >
전에이 >(cat)
필요하다. 이것은 echo
@Caleb의 답변에서와 같이 다시 명확하게 설명 될 수 있습니다 .
$ echo >(cat)
/dev/fd/63
그래서, 추가하지 않고 >
, date >(cat)
같은 것 date /dev/fd/63
stderr에 메시지를 인쇄 할 수있다.
당신은 단지 매개 변수로 파일 이름을 소요하고 처리하지 않는 프로그램이 가정 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
에는 이와 동등한 형식이 존재하지 않으며,이 경우 프로세스 대체 대신 사용할 수있는 것이 없습니다 (물론 명명 된 파이프 또는 임시 파일을 사용할 수도 있지만 이는 또 다른 것입니다) 이야기).