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

エコーまたは印刷 /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}"試しましたが成功しませんでした。

ベストアンサー1

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))。

読み取り+書き込みモードで端末デバイスを開く特別な場合を除き、stdoutとstderrは通常読み取り用に開かれません。使用できるストリームでなければなりません。に手紙を書く。したがって、ファイル記述子1からの読み込みは通常は機能しません。 Linuxでは、オープンまたは読み取り(図を参照)が機能し、stdoutが移動するファイルから読み取ることができます(stdoutがパイプの場合は/dev/stdoutパイプのもう一方の端から読み取られます。ソケットインターフェイスの場合は失敗します)。なぜならできないからです/dev/stderr$(</dev/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)"

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から何も読み取られないことがわかります。たとえば、大きなテキストを描いた場合:outwhat I read from stdin: foo\nout

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の後に何を読み取るかを決定します。

おすすめ記事