/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}"
시도했지만 성공하지 못했습니다.
답변1
stdin
, stdout
그리고 stderr
그렇습니다개울부착파일 설명자프로세스에 대해 각각 0, 1, 2입니다.
터미널이나 터미널 에뮬레이터의 대화형 쉘 프롬프트에서 3개의 파일 설명자는 모두 동일한 파일 설명자를 참조합니다.파일 설명 열기/dev/pts/0
이는 읽기+쓰기 모드에서 터미널 또는 의사 터미널 장치 파일(유사)을 열어 얻을 수 있습니다.
리디렉션을 사용하지 않고 대화형 셸에서 스크립트를 실행하면 스크립트가 이러한 파일 설명자를 상속합니다.
Linux에서 , /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)
).
읽기+쓰기 모드에서 터미널 장치를 여는 특별한 경우를 제외하고 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/pts/0을 열고 빈 줄을 $(</dev/stdin)
누를 때까지 입력한 내용을 읽습니다 . ^D
그런 다음 확장에 전달된 확장(후행 줄 바꿈 및 분할+glob이 포함된 입력)을 전달한 echo
다음 이를 표준 출력(표시용)으로 출력합니다.
그러나:
echo $(</dev/stdout)
존재하다 bash
(그리고 bash
오직$(...)
), 내부적으로 stdout이 리디렉션되었음을 인식하는 것이 중요합니다 . 이제는 파이프라인입니다. 의 경우 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
, 에서 읽고 싶지 않고 대신 stdin, stdout 및 stderr에서 읽으려는 경우 /dev/stdout
( /dev/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
printf
이전 항목이 with의 내용을 덮어쓰고 그 이후에는 해당 파일의 stdout 위치를 그대로 두었기 때문에 stdout에서 아무것도 읽히지 않는다는 것을 알 수 있습니다 . 예를 들어, 더 큰 텍스트를 그린 경우:out
what I read from stdin: foo\n
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
stdout
그리고 stderr
출력이므로 읽을 수는 없고 쓰기만 할 수 있습니다. 예를 들어:
echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr
프로그램은 기본적으로 표준 출력에 기록하므로 첫 번째 출력은 다음과 같습니다.
echo "this is stdout"
다른 방법으로 stderr를 리디렉션할 수 있습니다.
echo "this is stderr" 1>&2
답변3
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
.