各言語の標準エラー出力
そういえば今まで意識しなかったな、ということで、各言語の標準エラー出力を使ってみたメモ。
環境
手元にあるものということで、環境は以下のものに限定する。
- CentOS 7
- Java (openjdk version "1.8.0_151")
- C (gcc (GCC) 4.8.5)
-std=gnu11
でコンパイル
- C++ (g++ (GCC) 4.8.5)
-std=gnu++1y
でコンパイル
- PHP (PHP 5.4.16 (cli))
- Python 2 (Python 2.7.5)
- Python 3 (Python 3.6.3)
- ソースからビルドしたもの
- Ruby (ruby 2.0.0p648)
- Perl (v5.16.3)
- Go (go version go1.8.3 linux/amd64)
- bash (4.2.46(1)-release)
- Awk (GNU Awk 4.0.2)
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::cerr
とstd::clog
が標準エラー出力にそれぞれ関連付いている。
std::cerr
とstd::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"
が標準エラー出力。
まぁ、標準入力や標準出力を明示することはほとんどないけど。