web-dev-qa-db-ja.com

エコーまたは印刷/ dev / stdin / dev / stdout / dev / stderr

/ 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}"_を使用している人々が他のいくつかの質問でも見つけたが、成功せずに試してみた。

13
Omar BISTAMI

stdinstdout、およびstderrファイル記述子 0、1に接続されたstreamsですおよびプロセスの2。

端末または端末エミュレータのインタラクティブシェルのプロンプトでは、これらの3つのファイル記述子はすべて、端末または疑似端末デバイスファイルを開いて取得したものと同じ open file description を参照します(読み取り+書き込みモードの_/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)では、シェルはstdinから読み取っていません。stdinで開いているファイルと同じファイルを読み取るために新しいファイル記述子を開きます(したがって、stdinが現在指している場所ではなく、ファイルの先頭から読み取ります)に)。

端末デバイスが読み取り+書き込みモードで開かれている特別な場合を除いて、stdoutとstderrは通常、読み取り用に開かれていません。それらはあなたがに書き込むストリームを意味します。したがって、ファイル記述子1からの読み取りは、通常は機能しません。 Linuxでは、読み取りのために_/dev/stdout_または_/dev/stderr_を開いて($(</dev/stdout)のように)機能し、stdoutが移動するファイルから読み取ることができます(stdoutがパイプの場合、パイプのもう一方の端から読み取り、それがソケットの場合、openソケットできないため失敗します。

ターミナルの対話型シェルのプロンプトでリダイレクトなしで実行されるスクリプトの場合、/ 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のみ )では、$(...)内で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_、_/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)"
_

次のように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は失敗します。これは、ファイル記述子がwriteのみで開かれていて、$(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
_

以前のprintfoutの内容を_what I read from stdin: foo\n_で上書きし、その直後にそのファイル内のstdoutの位置を残したため、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の後に残ったものをどのように読み取ったかを確認し、それによってstdout位置もそれを超えて移動しましたそのため、次のprintfは後で読み取ったものを出力します。

29

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
2
Michael Daffin

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

おそらく、最初にfilanSudo apt install socatでインストールする必要があります。

1
wisbucky