다음을 이해하는 방법이 궁금합니다.
명령의 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 스트림으로 리디렉션합니다. 프로세스 대체는 명령을 실행하고 출력을 특수 임시 파일에 저장 한 다음 명령 대신 해당 파일 이름을 전달합니다. 어떤 명령을 사용하든 파일 이름으로 취급합니다. 생성 된 파일은 일반 파일이 아니라 더 이상 필요하지 않으면 자동으로 제거되는 명명 된 파이프입니다.
댓글
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
위에 언급 된 것 외에는 그러한 동등한 형식이 존재하지 않으며,이 경우 프로세스 대체 대신 사용할 수있는 것이 없습니다 (물론 이름이 지정된 파이프 또는 임시 파일이지만 이는 또 다른 이야기입니다.
[[ -p <(date) ]] && echo true
. bash 4.4 또는 3.2로 실행할 때true
가 생성됩니다.