私はシステムコールを「読む」ためにstdout fdを渡しましたが、それでもうまくいきます。

私はシステムコールを「読む」ためにstdout fdを渡しましたが、それでもうまくいきます。

1(stdout)/ 2(stderr)をreadシステムコールに渡しましたが、まだうまくいきます。それから0(stdin)をwriteシステムコールに渡し、それがうまくいくことがわかりました!

int main(int argc, char** argv){
    char buf[1024] = "abcdefghi\n";

    write(0, buf, 10);

    char readbuf[1024] = {0};
    // read(1, readbuf, 10); works too
    read(2, readbuf, 10);
    write(2, readbuf, 10);

    return 0;
}

出力:

abcdefghi
hey stdin  <-- I input this
hey stdin

とても混乱しています。これはバグだと思います。

実験:

それからfd 2をリダイレクトしようとしています。

$ ./a.out 2>/dev/null

この読み取りまたは第2の書き込みはすべて「表示」されません。出力は次のとおりです

abcdefgi

もしそうなら、stderrを読み込みに使用できますか?

次に、stdoutとstderrを閉じて、stdinのコピーを2つ作成します。

int main(int argc, char** argv){
    char buf[1024] = "abcdefghi\n";

    close(1);
    close(2);

    dup2(0, 1);
    dup2(0, 2);

    write(0, buf, 10);

    char redbuf[1024] = {0};
    read(2, redbuf, 10);
    write(2, redbuf, 10);

    return 0;
}

再び動作します。

出力:

abcdefghi
hey stdin  <-- I input this
hey stdin

それでは、stdinを書き込みに使用できますか?

ここに説明が必要です。

質問

私は知りたいです:

なぜstdout / stderrを使って読むことができますか?

なぜstdinを使って書くことができますか?

三流です(標準入力、標準出力、標準エラー)内部一つ小川?

そうでなければ、なぜこのような結果が出るのでしょうか?

答え1

唯一のルールは、入力/出力/エラーにfd 0/1/2を使用することです。リダイレクトなしでプログラムを呼び出すと、3つすべてがttyを参照し、ttyは読み取りおよび書き込みアクセスで開きます。つまり、必要に応じて読み書きできます。式ストリームは通常、FILECやstreamC ++などのより高いレベルのI / Oに使用されますが、同じストリームと呼ばれることがあります。

これが、リダイレクトの有無にかかわらず、どちらの例も入力したテキストをエコーする理由です。

一方、リダイレクトされると、シェルは読み取り専用または書き込み専用アクセスでファイルを開きます。あなたの例ではリダイレクトされず、画面に表示されるため、./a.out 2>/dev/null書き込みは端末に接続されています。0読み取りは2書き込みにのみ接続されるため/dev/null失敗する必要がありますが、プログラムの違いは不明です。書き込みは2成功しましたが、に書き込みます/dev/null。誤った読み取りと有効な書き込みは/dev/null端末に表示されません。

答え2

stdin/stdout/stderrをリダイレクトしない限り、これらのファイル記述子はログインプロセスによって開き、関連する読み書きファイルは最初のファイルttyとして開き(結果的にファイル記述子#0になります)、dup()2回呼び出されます。 stdout および stderr ファイル記述子を取得します。

で述べたようにユーザーコマンドを読み取ることができますが、標準入力からデータを「少なく」取得する方法は何ですか?過去には(以前に/dev/tty取り上げたUNIXmore確認を要求したときに読んだのと同じプログラムがありました。stderr

関連情報