!["echo 123 >(cat)" 출력에 "/dev/fd/63"이 있는 이유는 무엇입니까?](https://linux55.com/image/112391/%22echo%20123%20%26gt%3B(cat)%22%20%EC%B6%9C%EB%A0%A5%EC%97%90%20%22%2Fdev%2Ffd%2F63%22%EC%9D%B4%20%EC%9E%88%EB%8A%94%20%EC%9D%B4%EC%9C%A0%EB%8A%94%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
$ 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
wait 가 없기 때문에 엄격하게 동일하지 않으므로 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
.
그러나 bash
for의 프로세스 리디렉션과 마찬가지로 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)
$