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


13

/ 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}"成功せず、それを試してみました。

回答:


29

stdinstdout、および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)、シェルでは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の対象)を渡し、echostdout(表示用)に出力します。

ただし:

echo $(</dev/stdout)

中にbashbashのみ)、その内部を認識することが重要だ$(...)、標準出力にリダイレクトされています。現在はパイプです。の場合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、あなたは標準入力から読みたかった、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ファイルディスクリプタがために開いていたので失敗した書き込みを、読んでいない、の拡張のみ$(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はstdoutから何も読み取られなかったことに気づくでしょう。なぜなら、以前は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

stdoutそしてstderr出力であり、それらから読み取ることはできず、それらに書き込むことしかできません。例えば:

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
ステファンChazelas

@ Michael-Daffin>ありがとう。標準出力と標準エラーを読みたい場合は、猫しか使用できません。(それらはファイルなので)、たとえば、最後に発生したエラーをユーザーに表示したいecho this is your error $(cat /dev/stderr)ですか?
Omar BISTAMI 2017年

@OmarBISTAMI stdoutおよびからは読み取れませんstderr。これらは出力です。
クサラナンダ

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.