반향 또는 인쇄 / dev / stdin / dev / stdout / dev / stderr


14

/ dev / stdin, / dev / stdout 및 / dev / stderr의 값을 인쇄하고 싶습니다.

다음은 간단한 스크립트입니다.

#!/bin/bash
echo your stdin is : $(</dev/stdin)
echo your stdout is : $(</dev/stdout)
echo your stderr is : $(</dev/stderr)

나는 다음 파이프를 사용합니다 :

[root@localhost home]# ls | ./myscript.sh
[root@localhost home]# testerr | ./myscript.sh

단지 $(</dev/stdin)나는 또한 질문의 사람들이 사용하는 일부 다른 사람을 발견했습니다, 작동하는 것 같다 : "${1-/dev/stdin}"성공없이 시도했다.

답변:


30

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/stderrstdin, 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의 내용은 outwith로 내용을 덮어 쓰고 그 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이후에 읽은 것을 출력.


2

stdoutstderr출력, 당신은 그들에게 쓸 수 그들로부터 읽지 않는있다. 예를 들면 다음과 같습니다.

echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr

프로그램은 기본적으로 stdout에 기록하므로 첫 번째 프로그램은

echo "this is stdout"

그리고 다른 방법으로 stderr을 리디렉션 할 수 있습니다

echo "this is stderr" 1>&2

1
Linux에서 stdout이 파이프 나 tty 장치와 같은 일부 문자 장치로 이동하지 않는 echo x것과 동일 echo x > /dev/stdout하지 않습니다. 예를 들어, stdout이 일반 파일로 이동하면 파일 echo x > /dev/stdout을 자르고 현재 stdout 위치 x\n에 쓰지 않고 내용을 x\n바꿉니다.
Stéphane Chazelas

@ Michael-Daffin> 감사합니다. stdout과 stderr을 읽으려면 고양이 만 사용할 수 있습니까? (파일이기 때문에) 예를 들어 사용자에게 마지막으로 발생한 오류를 표시하고 싶습니다 echo this is your error $(cat /dev/stderr).
Omar BISTAMI

@OmarBISTAMI stdoutstderr에서 읽을 수 없으며 출력입니다.
Kusalananda

1

myscript.sh :

#!/bin/bash
filan -s

그런 다음 다음을 실행하십시오.

$ ./myscript.sh
    0 tty /dev/pts/1
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh
    0 pipe 
    1 tty /dev/pts/1
    2 tty /dev/pts/1

$ ls | ./myscript.sh > out.txt
$ cat out.txt
    0 pipe 
    1 file /tmp/out.txt
    2 tty /dev/pts/1

당신은 아마 설치해야합니다 filan으로 sudo apt install socat처음.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.