$ echo 123 | cat
123
내가 예상한 대로 실행 중입니다. 두 명령 모두 동일한 셸 내에서 실행됩니다.
>( ... )
그러나 셸에 있는 한 명령의 출력을 하위 셸에 있는 두 번째 명령의 출력에 연결하는 표현식을 사용하여 이를 연결하면 다음과 같은 결과가 나타납니다.
$ echo 123 >(cat)
123 /dev/fd/63
이는 다른 값에서도 마찬가지입니다.
$ echo 101 >(cat)
101 /dev/fd/63
$ echo $BASHPID >(cat)
3252 /dev/fd/63
나는 command1 >(command2)
과 같다고 생각했지만 command1 | command2
에서는 command1 >(command2)
각 명령이 다른 셸 안에 있으므로 동일한 출력을 가져야 합니다. 내가 어디 잘못 됐나요?
답변1
프로세스 대체는 >(thing)
파일 이름으로 대체됩니다. 이 파일명은 thing
대체 내부 의 표준 입력에 연결되는 파일에 해당합니다 .
다음은 그 사용에 대한 더 나은 예입니다.
$ sort -o >(cat -n >/tmp/out) ~/.profile
이렇게 하면 파일이 정렬 ~/.profile
되고 행을 열거 cat -n
하고 결과가 /tmp/out
.
따라서 질문에 대답하자면 다음과 같습니다. echo
두 개의 인수 123
와 를 가져오기 때문에 해당 출력을 얻습니다 /dev/fd/63
. 프로세스 대체에서 프로세스 /dev/fd/63
의 표준 입력에 연결된 파일입니다 .cat
예제 코드를 약간 수정하면 다음과 같습니다.
$ echo 101 > >(cat)
이렇게 하면 표준 출력만 생성됩니다 101
( 의 출력은 의 echo
입력 역할을 하는 파일로 리디렉션되고 cat
해당 cat
파일의 내용이 표준 출력에 생성됩니다).
또한 cmd1 | cmd2
파이프라인 에서는 (사용 중인 셸 구현에 따라) cmd2
동일한 셸에서 전혀 실행되지 않을 수도 있습니다 . 설명하는 방식으로 작동하지만(동일 쉘), 서브 쉘을 생성합니다 ( 쉘 옵션이 설정되어 있고 작업 제어가 활성화되지 않은 경우).cmd1
ksh93
bash
cmd2
lastpipe
답변2
완전성을 위해
cmd1 >(cmd2)
대부분 동일하다
cmd1 | cmd2
쉘 yash
과 그 쉘에만 있습니다.
그 껍질에는>(cmd)
프로세스가 있습니다.리디렉션/ / >(cmd)
와 반대로ksh
bash
zsh
프로세스인치환.
cmd1 >(cmd2)
에서는 yash
가 를 기다리지 않기 때문에 엄격히 동일하지는 않습니다. cmd2
따라서 다음을 찾을 수 있습니다.
$ yash -c 'echo A >(cat); echo B'
B
A
$ yash -c 'echo A | cat; echo B'
A
B
이에 비해 프로세스치환파일 경로(일반적으로 명명된 파이프 또는 미리 생성된 파이프에 대한 fd /dev/fd/<x>
위치 <x>
)로 확장되며, 쓰기 위해 열면 출력을 cmd
.
프로세스 대체가 에 의해 도입되었지만 ksh
해당 셸에서는 이를 리디렉션에 대한 인수로 전달할 수 없습니다.
ksh -c 'cmd1 > >(cmd2)'
프로세스 리디렉션을 에뮬레이션하는 것이 yash
작동하지 않습니다. 여기서는 대체 결과로 생성된 파일 이름을 다음과 같은 명령에 인수로 전달해야 합니다.
ksh -c 'diff <(echo a) <(echo b)'
bash
이 기능은 및 에서 작동합니다 zsh
.
그러나 님 bash
의 프로세스 리디렉션과 마찬가지로 yash
쉘은 명령( )을 기다리지 않습니다 cmd2
. 그래서:
$ bash -c 'echo A > >(cat); echo B'
B
A
ksh
프로세스 대체는 다음을 yash
사용하여 에뮬레이트할 수 있습니다.
cmd1 /dev/fd/5 5>(cmd2)
좋다:
diff /dev/fd/3 3<(echo a) /dev/fd/4 4<(echo b)
답변3
왜냐하면그게 바로 프로세스 대체가 하는 일이에요을 사용하면 대체 항목 내부의 명령이 파일 이름으로 표시됩니다. 내부적으로는 파이프를 통해 명령을 연결하여 /dev/fd/NN
기본 명령에 대한 경로를 제공하므로 이미 열려 있는 파일 설명자를 파이프에 열 수 있습니다.
파이프와는 다릅니다. 파이프는 파일 이름처럼 보이는 어떤 것도 포함하지 않고 stdout
연결 됩니다. stdin
프로세스 대체는 하나의 명령줄에 이러한 대체를 여러 개 가질 수 있다는 점에서 더 유연하지만 파일을 이름으로 열려면 기본 명령이 필요합니다(예: cat
가 아닌 echo
).
다음과 같이 프로세스 대체를 사용하여 파이프를 에뮬레이트할 수 있습니다.
echo foo > >(cat -n)
답변4
$ echo 1 >(cat > /dev/null)
1 /dev/fd/63
$ echo echo >(cat /dev/null)
echo /dev/fd/63
# We can trace how the commands are executed
# so long as we avoid using shell builtin commands,
# and run the equivalent external program instead, i.e. /usr/bin/echo
$ strace -f -e execve bash -c '/usr/bin/echo >(cat /dev/null)'
execve("/usr/bin/bash", ["bash", "-c", "/usr/bin/echo >(cat /dev/null)"], [/* 56 vars */]) = 0
strace: Process 4213 attached
[pid 4212] execve("/usr/bin/echo", ["/usr/bin/echo", "/dev/fd/63"], [/* 56 vars */]) = 0
strace: Process 4214 attached
[pid 4214] execve("/usr/bin/cat", ["cat", "/dev/null"], [/* 56 vars */]/dev/fd/63
) = 0
[pid 4212] +++ exited with 0 +++
[pid 4214] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4214, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
# Apparently, the order of evaluation is arranged so this works nicely:
$ echo 1 > >(cat > /dev/null)
$