HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

各言語の標準エラー出力

そういえば今まで意識しなかったな、ということで、各言語の標準エラー出力を使ってみたメモ。

環境

手元にあるものということで、環境は以下のものに限定する。

Java

import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        byte[] buf = new byte[1024];
        int len;
        while ((len = System.in.read(buf)) > 0) {
            System.err.write(buf, 0, len);
        }
    }
}

System.inが標準入力、System.outが標準出力、System.err標準エラー出力を表す。

ちなみに、System.setIn(InputStream)System.setOut(PrintStream)System.setErr(PrintStream)というのがあるので、例えば標準出力や標準エラー出力をファイルに書き出すように切り替えるとかも可能。

C

#include <stdio.h>

int main(int argc, char** argv) {
    char buf[1024];
    while (fgets(buf, sizeof(buf), stdin)) {
        fputs(buf, stderr);
    }
    return 0;
}

FILE*型だと、stdinが標準入力、stdoutが標準出力、stderr標準エラー出力

ちなみに、int型のファイルディスクリプタ(fd)だと、0が標準入力、1が標準出力、2標準エラー出力に関連付いている。 unistd.hを見ると、以下のように書いてある。

/* Standard file descriptors.  */
#define STDIN_FILENO    0       /* Standard input.  */
#define STDOUT_FILENO   1       /* Standard output.  */
#define STDERR_FILENO   2       /* Standard error output.  */

C++

#include <iostream>

using namespace std;

int main(int argc, char** argv) {
    char buf[1024];
    while (cin.getline(buf, sizeof(buf))) {
        cerr << buf << endl;
    }
    return EXIT_SUCCESS;
}

std::cinが標準入力、std::coutが標準出力、std::cerrstd::clog標準エラー出力にそれぞれ関連付いている。 std::cerrstd::clogの違いは、前者がバッファリングされないのに対して、後者がバッファリングされるというもの。 iostreamを見ると、以下のように書いてある。

namespace std _GLIBCXX_VISIBILITY(default)
{
  // (中略)
  extern istream cin;           /// Linked to standard input
  extern ostream cout;          /// Linked to standard output
  extern ostream cerr;          /// Linked to standard error (unbuffered)
  extern ostream clog;          /// Linked to standard error (buffered)

std::clogの存在は、このヘッダファイルを見て初めて知った。

PHP

<?php

$str = file_get_contents('php://stdin');
file_put_contents('php://stderr', $str);

PHPはどちらかというとWebアプリ開発に使われる言語ということで、特に意識せずにprintとかすると標準出力に書き出されるので、標準入出力を意識することは少ないかもしれない。

'php://stdin'が標準入力、'php://stdout'が標準出力、'php://stderr'標準エラー出力を表すので、これをfile_get_contents / file_put_contentsやfopen等にファイル名と同様に指定してやればよい。

Python 2

import sys

while True:
    line = sys.stdin.readline()
    if line == '':
        break
    sys.stderr.write(line)

sys.stdinが標準入力、sys.stdoutが標準出力、sys.stderr標準エラー出力

Python 3

import sys

while True:
    line = sys.stdin.buffer.readline()
    if line == b'':
        break
    sys.stderr.buffer.write(line)

sys.stdinが標準入力、sys.stdoutが標準出力、sys.stderr標準エラー出力

Ruby

while line = STDIN.gets
    STDERR.puts line
end

STDINが標準入力、STDOUTが標準出力、STDERR標準エラー出力

Perl

while ((my $line = <STDIN>)) {
    print STDERR $line;
}

STDINが標準入力、STDOUTが標準出力、STDERR標準エラー出力

Go

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    stdin := bufio.NewReader(os.Stdin)
    stderr := bufio.NewWriter(os.Stderr)
    for {
        ch, err := stdin.ReadByte()
        if err == io.EOF {
            break
        }
        stderr.WriteByte(ch)
    }
    stderr.Flush()
}

os.Stdinが標準入力、os.Stdoutが標準出力、os.Stderr標準エラー出力

bash

#! /bin/bash

cat <&0 >&2

0が標準入力、1が標準出力、2標準エラー出力を表すので、標準エラー出力に出したい場合は、>&2のように書いてリダイレクトしてやればよい。

/dev/stdin/dev/stdout/dev/stderrを使う手もあるので、>> /dev/stderrのようにリダイレクトしてもよい。

Awk

{
    print >> "/dev/stderr";
}

"/dev/stdin"が標準入力、"/dev/stdout"が標準出力、"/dev/stderr"標準エラー出力

まぁ、標準入力や標準出力を明示することはほとんどないけど。