나는 기능적으로 동일하다고 생각되는 두 구조 사이의 차이점을 일으키는 원인을 이해하려고 노력하고 있습니다.
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
stdout: stderr: foo
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
stderr: foo
편집: user1133275를 올바르게 이해했다면 그는 표준 출력으로 출력하지 않으면 >(sed 's/^/stdout: /')
하위 쉘이 ( echo foo >&2 )
실행되지 않을 것이라고 제안했습니다. 그러나 이는 다음을 의미합니다.
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(echo baz)
baz
stderr: foo
표시되어서는 안 됩니다 baz
.
stdout:
편집 2: 아마도 흥미롭게도 sed는 파이핑할 때에도 빈 입력에 대해 출력 하지 않습니다 .
$ sed 's/^/stdout: /' < /dev/null
$ printf "" | sed 's/^/stdout: /'
$
답변1
첫 번째 명령,
( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
단순화된 형식(생성된 데이터를 저장하기 위해 임시 파일 사용 echo
):
{ echo foo 2>file >&2; sed 's/^/stderr: /' file; } | sed 's/^/stdout: /'
즉, 첫 번째는 sed
표준 오류의 결과 내용을 읽고 echo
이를 표준 출력에 쓰고, 두 번째는 sed
이를 읽고 수정합니다.
두 번째 명령은
( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
단순화된 형태로,
echo foo 2>file >&2; sed 's/^/stderr: /' file; sed 's/^/stdout: /' </dev/null
여기서 sed
stderr를 얻는 것은 출력을 생성하는 반면, stderr(아무 것도 없음)을 얻는 다른 것은 sed
출력을 생성하지 않습니다(입력을 얻지 못하고 데이터가 삽입되거나 추가되지 않기 때문입니다).
다른 표현으로는:
첫 번째 명령:
( echo foo >&2 ) 2>file
sed 's/^/stderr: /' file | sed 's/^/stdout: /'
두 번째 명령:
( echo foo >&2 ) 2>file >otherfile
sed 's/^/stderr: /' file
sed 's/^/stdout: /' otherfile
즉, sed
두 명령 중 두 번째 명령은 아무것도 읽지 않습니다. 특히, 첫 번째 명령과 마찬가지로 첫 번째 명령의 출력을 읽지 않습니다 sed
.
매우 단순화된 표기법을 사용하면 첫 번째 명령은 다음과 같습니다.
utility-writing-to-stderr 2> >(something1) | something2
이는 something1
표준 출력에 기록되고 something2
.
두 번째 명령은 동일한 표기법을 사용합니다.
utility-writing-to-stderr 2> >(something1) >(something2)
즉 , 서로 연결되어 something1
있지도 않고 어떤 방식으로든 생성되는 내용을 읽을 수 없습니다. 게다가 표준 출력 스트림에서는 아무 것도 생성되지 않으므로 표준 입력에서 아무것도 읽을 수 없습니다.something2
something2
something1
utility-writing-to-stderr
something2
답변2
>
쉘의 리디렉션 순서로 인해 작동 ( echo foo >&2 )
하고 |
작동합니다 . >(sed 's/^/stderr: /')
예를 들어
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /' > >(sed 's/^/stdout: /') )
stdout: stderr: foo
또는
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | cat > >(sed 's/^/stdout: /')
stdout: stderr: foo
명확한 예를 들어 질문을 순서대로 작성하세요.
$ ( ( echo foo >&2 ) > >(sed 's/^/stdout: /') ) 2> >(sed 's/^/stderr: /')
stderr: foo
또는
$ ( ( echo foo >&2 ) | sed 's/^/stdout: /' ) 2> >(sed 's/^/stderr: /')
stderr: foo
답변3
이 두 명령은 동일하지 않습니다.
명령(1):
( one ) 2> >(two) | three
(std) 출력을 two
다음으로 보냅니다 three
(stderr에 대한 자세한 내용은 아래 참조).
명령(2):
( one ) 2> >(two) > >(three)
(std) 출력을 (stderr ) one
로 보냅니다 .three
two
가슴 아픈 세부 사항은 다음과 같습니다.
명령 1:( one ) 2> >(two) | three
- 명령
three
start(sed 's/^/stdout: /'
)는 표준 입력의 입력을 기다립니다. 2
(stderr
)stdin
는 ~ 로 리디렉션됩니다two
.one
내부 리디렉션(echo foo >&2
)이 발생했습니다.- 명령이 실행됩니다
foo
(stderr
표준 출력으로 전송되지 않음). - 단어는
foo
( of )에서 ( of )로 리디렉션됩니다.stderr
one
stdin
two
- 두 명령을 실행하십시오 (
sed 's/^/stderr: /'
) two
Modified() 출력이stderr: foo
이제 stdout 으로 전송됩니다two
.- 현재 표준 출력은
two
파이프를 통해 도착합니다three
. three
입력 명령이 처음부터 출력을 받기를 기다립니다.- 출력이 수정되고 리더가 추가됩니다
stdout:
. - 마지막 문자열은
stdout: stderr: foo
tty로 이동합니다.
명령 2: (1) 2 >> (2) >> (3)
- 마지막 리디렉션(
>
)이 먼저 빌드됩니다. - 명령이
three
입력 대기를 시작합니다.stdin
오직(>()
). - 이 명령
three
은오직표준 출력one
. - 명령이
two
입력 대기를 시작합니다. - 이 명령은
two
(오직) 표준 에러one
. - 내부 리디렉션은 stdout을
one
여기에 연결합니다stderr
. - 명령은 (of ) 로
one
전송되어 실행됩니다 .foo
stderr
one
foo
가다two
two
수신된 문자열을 변경하여stderr: foo
다음으로 보냅니다.단말기.three
stdout 에서 빈 입력을 받습니다one
.three
인쇄아무것도 없다(처리할 행이 없기 때문입니다.)
이 명령에 대해 알아보세요:
printf '' | sed 's/^/initial: /'
출력이 없습니다(그리고 작동하게 할 방법도 없습니다).
변경 순서: 명령 3: (1) >>(3) 2>>(2)
two
연습으로 three
세부사항 출력 대신 에 이동 하십시오.tty
답변4
나는 @Kusalananda의 매우 명확한 답변에 동의하지만 직장에서 프로세스 대체의 작은 예로서 그의 답변에 이것을 추가할 위험이 있습니다.
두 번째 제안은 작은 인쇄상의 변경(및 잘못된 논리의 비교적 큰 변경)으로 구현될 수 있습니다.
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
stderr: foo # for the well explained reason above
하지만:
v vv
$ ( (echo foo >&2) 2> >(sed 's/^/stderr: /') )> >(sed 's/^/stdout: /')
stdout: stderr: foo
( )>
표시된 대로 추가하면(또는 >( )
둘 다 잘 작동함) 실제로 프로세스 대체를 통해 출력을 입력으로 리디렉션할 수 있는 파일을 생성할 수 있기 때문입니다 >(sed 's/^/stdout: /')
.
다른 프로세스 교체 내에 프로세스 교체를 포함하는 방법을 설명하기 위해 이것을 추가하는 것을 고려했습니다. 가독성을 위해 나는아니요더 높은 수준의 임베딩으로 푸시합니다. 하지만 어떤 이유로든 피해야 하는 경우관로그리고 관련껍데기, 이는 좋은 해결책입니다.