stdin
Goプログラムの原文から読みたいです。たとえば、私がした場合echo test stdin | go run test.go
、「test stdin」にアクセスしたいと思うでしょう。から読み込もうとしましos.Stdin
たが、何も入っていない場合は入力待ちになります。最初にサイズも確認してみましたが、os.Stdin.Stat().Size()
入力が渡されても 0 です。
私に何ができる?
stdin
Goプログラムの原文から読みたいです。たとえば、私がした場合echo test stdin | go run test.go
、「test stdin」にアクセスしたいと思うでしょう。から読み込もうとしましos.Stdin
たが、何も入っていない場合は入力待ちになります。最初にサイズも確認してみましたが、os.Stdin.Stat().Size()
入力が渡されても 0 です。
私に何ができる?
を使用して stdin から読み取るos.Stdin
と、期待どおりに動作するはずです。
package main
import "os"
import "log"
import "io/ioutil"
func main() {
bytes, err := ioutil.ReadAll(os.Stdin)
log.Println(err, string(bytes))
}
実行echo test stdin | go run stdin.go
すると、「test stdin」が正常に出力されるはずです。
発生した問題を特定するために使用したコードを添付していただけると助かります。
行ベースの読み取りには、次を使用できますbufio.Scanner
。
import "os"
import "log"
import "bufio"
func main() {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
log.Println("line", s.Text())
}
}
「初期標準入力」などがないため、あなたの質問自体には賢明な答えはないと思います。Unix ライクな OS と Windows は、「標準ストリーム」の概念を実装しています。これは次のように機能します (簡略化): プロセスが作成されると、自動的に 3 つのファイル記述子 (Windows ではハンドル) が開かれます — stdin、stdout、および stderr。間違いなく、あなたはこの概念に精通していますが、そこで「ストリーム」という言葉の意味を強調したいと思います - あなたの例では、あなたが呼び出すとき
$ echo 'test stdin' | ./stdin
シェルはpipeを作成し、 2 つのプロセス (1 つはバイナリ用echo
、もう 1 つはバイナリ用) を生成し、作成したパイプを使用します。パイプの書き込み FD はecho
の stdout に接続され、パイプの読み取り FD はバイナリの stdin に接続されます。次に、echo
プロセスが標準出力に書き込もうとするものはすべて、プロセスの標準入力にパイプされます (sic!)。(実際には、今日のほとんどのシェルecho
は組み込みプリミティブとして実装されていますが、これはセマンティクスをまったく変更しません/bin/echo
。実際のプログラムである代わりに試してみることもできます。また、私はあなたのプログラムを参照していたことに注意し./stdin
てください—これは明確にするためgo run stdin.go
であり、最終的にはまさにこれを行います。)
ここでいくつかの重要なことに注意してください。
echo
あなたの場合)は、標準出力に何も書き込む必要はありません(たとえば、標準出力にecho -n
何も書き込まず、正常に終了しません)。read
が試行されて失敗した後でのみ)。これをまとめましょう。観察している動作は正しく、正常です。stdin から何らかのデータを取得することを期待している場合、すぐに利用できると期待してはなりません。標準入力でもブロックしたくない場合は、無限ループで標準入力からの読み取りをブロックするゴルーチンを作成し (ただし、EOF 条件をチェックします)、収集したデータをチャネル経由で渡します (場合によっては、特定の処理の後、必要)。
1これが、パイプライン内の 2 つのパイプ間で通常発生する特定のツール ( など) にgrep
、各行の書き込み後に stdout をフラッシュする特別なオプションがある場合がある理由です — 1 つの例については、マニュアルページ--line-buffered
のオプションについて読んでください。この「デフォルトでの完全なバッファリング」セマンティクスを認識していない人は、監視対象のファイルが更新されたことが明らかな場合に、なぜストールして何も表示されないように見えるのか困惑しています。grep
tail -f /path/to/some/file.log | grep whatever | sed ...
補足として、次のように、バイナリを「そのまま」実行する場合
$ ./stdin
これは、生成されたプロセスが stdin (または「初期 stdin」または whaveter) を持たないという意味ではありません。代わりに、その stdin は、シェルがキーボード インポートを受け取るのと同じストリームに接続されます (したがって、プロセスの stdin に何かを直接入力できます)。 )。
プロセスの標準入力をどこにも接続しない唯一の確実な方法は、
$ ./stdin </dev/null
Unix ライクな OS および
C:\> stdin <NUL
Windows で。この「null デバイス」read
により、プロセスは標準入力から最初に EOF を認識します。
標準入力の内容を確認することはできませんが、標準入力が端末またはパイプに関連付けられているかどうかを確認できます。IsTerminal は、標準の unix fd 番号 (0,1,2) だけを受け取ります。syscall パッケージには変数が割り当てられているため、名前を付けたい場合は syscall.Stdin を実行できます。
package main
import (
"code.google.com/p/go.crypto/ssh/terminal"
"fmt"
"io/ioutil"
"os"
)
func main() {
if ! terminal.IsTerminal(0) {
b, _ := ioutil.ReadAll(os.Stdin)
fmt.Print(string(b))
} else {
fmt.Println("no piped data")
}
}