私はこれをするのに慣れています。
someprogram >output.file
私はプログラムで生成された出力をファイルに保存したいときはいつでもこれを行います。私もこれの2つのバリエーションを知っていますIOリダイレクト:
someprogram 2>output.of.stderr.file
(標準誤差の場合)someprogram &>output.stderr.and.stdout.file
(stdout + stderrの組み合わせの場合)
今日は不可能だと思った状況に直面しました。次のコマンドを使用すると、期待xinput test 10
どおりに次の結果が表示されます。
user@hostname:~$xinput テスト 10 ボタン30 リリースキー30 ボタン40 キーリリース40 ボタン32 キーリリース32 ボタン 65 キーリリース65 ボタン61 キーリリース61 ボタン 31 ^C ユーザー@ホスト名:~$
私はこの出力がいつものようにファイルに保存されることを期待しました。たとえば、.を使用しましたが、xinput test 10 > output.file
私の期待とは異なり、出力.ファイルファイルは空でした。これはまた、xinput test 10 &> output.file
stdoutやstderrで何かを見逃さないようにするためです。
本当に混乱しています。xinput
出力がリダイレクトされるのを防ぐ方法があるかどうか、ここでプログラムに問い合わせてみましょう。
修正する
ソースコードを見ました。このコードによって出力が生成されたようです(下記のコードスニペットを参照)。出力は通常のprintfによって生成されるようです。
//test.c ファイルから 静的無効 print_events(*dpy 表示) { XEventイベント; そして(1){ XNextEvent(dpy、&イベント); // [...いくつかの異なるイベントタイプがここにリストされています...] if((Event.type == key_press_type) || (Event.type == key_release_type)) { 整数ループ; XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event; printf("key %s %d ", (Event.type == key_release_type) ? "release" : "押された", key->keycode); for(loops=0;loopaxes_count;loop++){ printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]); } printf("\n"); } } }
stderrから出力コピーを取得できるように、ソースコードをこれ(以下の次のコードスニペットを参照)に変更しました。この出力をリダイレクトできます。
//test.c ファイルから 静的無効 print_events(*dpy 表示) { XEventイベント; そして(1){ XNextEvent(dpy、&イベント); // [...いくつかの異なるイベントタイプがここにリストされています...] if((Event.type == key_press_type) || (Event.type == key_release_type)) { 整数ループ; XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event; printf("key %s %d ", (Event.type == key_release_type) ? "release" : "押された", key->keycode); fprintf(stderr,"key %s %d ", (Event.type == key_release_type) ? "release" : "press ", key->keycode); for(loops=0;loopaxes_count;loop++){ printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]); } printf("\n"); } } }
現在の私の考えは、リダイレクトを実行すると、プログラムがメジャーリリースイベントを監視する機能を失う可能性があることです。
答え1
stdout が端末でない場合にのみ出力がバッファリングされます。
を押すと、Ctrl-Cそのバッファがまだ書き込まれていないため失われます。
何でも使用すると同じ動作が得られますstdio
。たとえば、次のようになります。
grep . > file
空でない行を入力してキーを押すと、Ctrl-Cファイルが空であることがわかります。
一方、次のように入力します。
xinput test 10 > file
その後、キーボードで十分に入力してください。バッファー全体(最小4k出力)を取得すると表示できます。文書一度に4kずつ増加します。
を使用すると、forと入力してバッファをフラッシュして正常にシャットダウンgrep
できます。の場合にはそんなオプションがないと思います。Ctrl-Dgrep
xinput
バッファリングはstderr
デフォルトでは行われないので、他の動作が発生する理由を説明します。fprintf(stderr)
にxinput.c
1つを追加すると、つまり受信時に正常に終了するように指示するsignal(SIGINT, exit)
と、もはやnullではないことがわかります(信号ハンドラでライブラリ関数を呼び出すことが安全であると保証されないため、競合しないと仮定)。 printfがバッファに書き込むかどうかを検討してください。これは、信号が領域に入ると発生します。xinput
SIGINT
file
可能であれば、次のstdbuf
コマンドを使用してバッファリング動作を変更できますstdio
。
stdbuf -oL xinput test 10 > file
持つこのサイトに質問がたくさんあります。このオーバーライドは無効になります。標準入出力バッファリングを入力すると、より多くの代替ソリューションを見つけることができます。
答え2
/dev/tty
一般的なリダイレクトが発生しないようにコマンドを直接作成できます。
$ cat demo
#!/bin/ksh
LC_ALL=C TZ=Z date > /dev/tty
$ ./demo >demo.out 2>demo.err
Fri Dec 28 10:31:57 2012
$ ls -l demo*
-rwxr-xr-x 1 jlliagre jlliagre 41 2012-12-28 11:31 demo
-rw-r--r-- 1 jlliagre jlliagre 0 2012-12-28 11:31 demo.err
-rw-r--r-- 1 jlliagre jlliagre 0 2012-12-28 11:31 demo.out
答え3
xinput
ファイル出力は拒否されますが、端末出力は拒否されているようです。これを達成するために、xinput
システムコールを使用できます。
int isatty(int fd)
開こうとしているファイル記述子が端末を参照していることを確認します。
しばらく前に私はというプログラムで同じ現象を偶然発見しましたdpic
。ソースコードを見てデバッグした後、関連する行を削除し、isatty
すべてが再び期待どおりに機能しました。
しかし、私はあなたの言葉に同意します。この経験は非常に衝撃的です。 ;)
答え4
はい。私はパスカルでプログラミングしていたDOS時代にもこのようなことをしました。私は次の原則がまだ有効だと思います。
- 標準出力を閉じる
- コンソールで標準出力を再度開く
- 標準出力に出力を書き込む
これは実際にすべてのパイプラインを中断します。