"echo 123 >(cat)" 출력에 "/dev/fd/63"이 있는 이유는 무엇입니까?

"echo 123 >(cat)" 출력에 "/dev/fd/63"이 있는 이유는 무엇입니까?
$ 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)에는 yashwait 가 없기 때문에 엄격하게 동일하지 않으므로 cmd2다음을 찾을 수 있습니다.

$ yash -c 'echo A >(cat); echo B'
B
A
$ yash -c 'echo A | cat; echo B'
A
B

이에 비해 과정은치환쓰기 위해 열 때 출력을 /dev/fd/<x>.<x>cmd

이 셸에는 프로세스 대체가 ksh도입되어 있지만 이를 리디렉션에 대한 인수로 전달할 수는 없습니다.

ksh -c 'cmd1 > >(cmd2)'

프로세스 리디렉션 시뮬레이션이 yash작동하지 않습니다. 거기에서 다음과 같이 대체 결과로 생성된 파일 이름을 명령에 대한 인수로 전달해야 합니다.

ksh -c 'diff <(echo a) <(echo b)'

그것은 bash안팎으로 작동 합니다 zsh.

그러나 bashfor의 프로세스 리디렉션과 마찬가지로 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)
$

관련 정보