stdin
, stdout
, 및 stderr
이다 스트림 에 첨부 파일 디스크립터 0, 1, 2는 각각의 공정.
터미널 또는 터미널 에뮬레이터의 대화식 쉘 프롬프트에서이 3 개의 파일 디스크립터는 모두 읽기 + 쓰기에서 터미널 또는 의사 터미널 장치 파일 (예 :)을 열어 얻은 동일한 열린 파일 설명 을 참조합니다. /dev/pts/0
방법.
대화식 쉘에서 리디렉션을 사용하지 않고 스크립트를 시작하면 스크립트가 해당 파일 설명자를 상속합니다.
리눅스에서 /dev/stdin
, /dev/stdout
, /dev/stderr
기호 링크는 /proc/self/fd/0
, /proc/self/fd/1
, /proc/self/fd/2
각각 스스로 그 파일 기술자에 열려있는 실제의 파일에 특별한 심볼릭 링크.
그것들은 stdin, stdout, stderr이 아니며 stdin, stdout, stderr이 어떤 파일을 식별 하는지를 나타내는 특수 파일입니다 (특별 파일이있는 Linux 이외의 다른 시스템에서는 다릅니다).
stdin에서 무언가를 읽는다는 것은 파일 디스크립터 0에서 읽는 것을 의미합니다 (이는 파일이 참조하는 파일 내의 임의 위치를 가리킴 /dev/stdin
).
그러나에서 $(</dev/stdin)
쉘은 stdin에서 읽지 않고 stdin에서 열린 파일과 동일한 파일을 읽기 위해 새 파일 설명자를 엽니 다 (따라서 stdin이 현재 가리키는 위치가 아닌 파일의 시작 부분부터 읽음).
읽기 + 쓰기 모드로 열린 터미널 장치의 특수한 경우를 제외하고 stdout 및 stderr은 일반적으로 읽기 위해 열리지 않습니다. 그것들은 당신이 쓰는 스트림입니다 . 따라서 파일 디스크립터 1에서 읽는 것은 일반적으로 작동하지 않습니다. Linux에서 (에서와 같이 ) 열거 /dev/stdout
나 /dev/stderr
읽기 위해 $(</dev/stdout)
작동하고 stdout이 이동하는 파일에서 읽을 수 있습니다 (stdout이 파이프 인 경우 파이프의 다른 쪽 끝에서 읽은 것입니다. 소켓을 열 수 없으므로 실패 합니다).
터미널의 대화식 쉘 프롬프트에서 리디렉션없이 스크립트를 실행하는 경우, / dev / stdin, / dev / stdout 및 / dev / stderr은 모두 / dev / pts / x 터미널 장치 파일이됩니다.
이러한 특수 파일을 읽으면 터미널에서 전송 한 내용 (키보드에 입력 한 내용)이 반환됩니다. 그들에게 글을 쓰면 텍스트가 터미널에 표시됩니다 (표시 용).
echo $(</dev/stdin)
echo $(</dev/stderr)
동일합니다. 확장하기 $(</dev/stdin)
위해 쉘은 / dev / pts / 0을 열고 ^D
빈 줄 을 누를 때까지 입력 한 내용을 읽습니다 . 그런 다음 확장 (후행 줄 바꿈을 제거하고 split + glob 대상으로 입력 한 것)을 전달 echo
한 다음 stdout (출력 )으로 출력합니다.
그러나
echo $(</dev/stdout)
에 bash
( 그리고 bash
유일한 )는 그 내부를 실현하는 것이 중요합니다 $(...)
, 표준 출력 리디렉션되었습니다. 이제 파이프입니다. 의 경우 bash
자식 셸 프로세스는 파일의 내용 (여기 /dev/stdout
)을 읽고 파이프에 쓰는 반면 부모는 다른 쪽 끝에서 읽어 확장을 구성합니다.
이 경우 해당 자식 bash 프로세스가 열리면 /dev/stdout
실제로 파이프의 읽기 끝이 열립니다 . 그 어떤 것도 나오지 않을 것입니다. 교착 상태입니다.
스크립트 stdout이 가리키는 파일에서 읽으려면 다음을 사용하여 해결하십시오.
{ echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1
그러면 fd 1이 fd 3에 복제되므로 / dev / fd / 3는 / dev / stdout과 동일한 파일을 가리 킵니다.
다음과 같은 스크립트로
#! /bin/bash -
printf 'content of file on stdin: %s\n' "$(</dev/stdin)"
{ printf 'content of file on stdout: %s\n' "$(</dev/fd/3)"; } 3<&1
printf 'content of file on stderr: %s\n' "$(</dev/stderr)"
다음과 같이 실행할 때 :
echo bar > err
echo foo | myscript > out 2>> err
out
나중에 볼 수 있습니다 :
content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar
/dev/stdin
,, /dev/stdout
에서 읽는 것과 반대로 /dev/stderr
stdin, stdout 및 stderr에서 읽기를 원한다면 (이는 덜 이해가됩니다) 다음을 수행하십시오.
#! /bin/sh -
printf 'what I read from stdin: %s\n' "$(cat)"
{ printf 'what I read from stdout: %s\n' "$(cat <&3)"; } 3<&1
printf 'what I read from stderr: %s\n' "$(cat <&2)"
두 번째 스크립트를 다시 시작한 경우 :
echo bar > err
echo foo | myscript > out 2>> err
당신은 볼 수 있습니다 out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr:
그리고 err
:
bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor
stdout 및 stderr의 cat
경우 파일 디스크립터가 읽기 전용이 아닌 쓰기 전용으로 확장되어 $(cat <&3)
있고 확장되어 $(cat <&2)
비어 있으므로 실패합니다 .
당신이 그것을 다음과 같이 불렀다면 :
echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err
(여기서 <>
, 당신이 볼 수있을 잘림없이 읽기 + 쓰기 모드로 열립니다) out
:
what I read from stdin: foo
what I read from stdout:
what I read from stderr: err
그리고 err
:
err
stdout에서 읽은 내용이 없다는 것을 알 수 있습니다. 이전 printf
의 내용은 out
with로 내용을 덮어 쓰고 그 what I read from stdin: foo\n
직후 stdout 위치를 떠났기 때문입니다. out
더 큰 텍스트로 시작한 경우 다음 과 같습니다.
echo 'This is longer than "what I read from stdin": foo' > out
그런 다음에 들어갈 것입니다 out
:
what I read from stdin: foo
read from stdin": foo
what I read from stdout: read from stdin": foo
what I read from stderr: err
(가) 방법을 참조하십시오 $(cat <&3)
최초의 후 남아 있었는지 읽기 printf
등 또한 과거의 표준 출력 위치를 이동하고 그래서 다음 printf
이후에 읽은 것을 출력.
echo x
것과 동일echo x > /dev/stdout
하지 않습니다. 예를 들어, stdout이 일반 파일로 이동하면 파일echo x > /dev/stdout
을 자르고 현재 stdout 위치x\n
에 쓰지 않고 내용을x\n
바꿉니다.