GNU/Linux >> Linux の 問題 >  >> Linux

オンザフライ出力リダイレクト、プログラムの実行中にファイルリダイレクト出力を確認

stdout から マニュアルページ:

<ブロック引用>

ストリーム stderr はバッファリングされません。ストリーム stdout は、端末を指す場合は行バッファリングされます .fflush(3) または exit(3) が呼び出されるか、改行が出力されるまで、部分的な行は表示されません。

結論:出力が端末でない限り、プログラムの標準出力はデフォルトで完全にバッファリングされたモードになります。これは基本的に、文字単位は言うまでもなく、行単位ではなく、大きなブロックでデータを出力することを意味します。

これを回避する方法:

  • プログラムを修正する:リアルタイムの出力が必要な場合は、プログラムを修正する必要があります。 C では fflush(stdout) を使用できます 各出力ステートメントの後、または setvbuf() 標準出力のバッファリングモードを変更します。 Python の場合は sys.stdout.flush() です

  • 完全な stdout リダイレクトではなく、PTY から記録できるユーティリティを使用します。 GNU Screen でこれを行うことができます:

    screen -d -m -L python test.py
    

    スタートでしょう。これにより、プログラムの出力が screenlog.0 というファイルに記録されます (または同様の)デフォルトの遅延が10秒の現在のディレクトリで、 screen を使用できます コマンドが実行されているセッションに接続して、入力を提供または終了します。ログファイルの遅延と名前は、構成ファイルで、またはバックグラウンド セッションに接続した後に手動で変更できます。

編集:

ほとんどの Linux システムでは、3 番目の回避策があります。LD_PRELOAD を使用できます。 変数とプリロードされたライブラリを使用して C ライブラリの選択関数をオーバーライドし、それらを使用して stdout を設定します。 これらの関数がプログラムによって呼び出されるときのバッファリング モード。この方法はうまくいくかもしれませんが、いくつかの欠点があります:

  • 静的実行可能ファイルではまったく機能しません

  • 壊れやすく、かなり醜いです。

  • SUID 実行可能ファイルではまったく機能しません。動的ローダーは LD_PRELOAD の読み取りを拒否します。 セキュリティ上の理由から、そのような実行可能ファイルをロードするときの変数。

  • 壊れやすく、かなり醜いです。

  • 後にプログラムによって呼び出されるライブラリ関数を見つけてオーバーライドする必要があります 最初に stdout を設定します バッファリング モード、できれば before 任意の出力。 getenv() 多くのプログラムに適していますが、すべてではありません。 printf() などの一般的な I/O 関数をオーバーライドする必要がある場合があります または fwrite() - プッシュが押し寄せてきた場合、バッファリング モードを制御するすべての関数をオーバーライドし、stdout の特別な条件を導入する必要がある場合があります。 .

  • 壊れやすく、かなり醜いです。

  • 望ましくない副作用がないことを確認するのは困難です。これを正しく行うには、 stdout のみを確保する必要があります 影響を受けており、オーバーライドがプログラムの残りの部分をクラッシュさせないことを確認してください。 stdout

  • もろくて醜いって言ったっけ?

とはいえ、プロセスは比較的簡単です。 Cファイルを入れます。 linebufferedstdout.c 置換関数:

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>


char *getenv(const char *s) {
    static char *(*getenv_real)(const char *s) = NULL;

    if (getenv_real == NULL) {
        getenv_real = dlsym(RTLD_NEXT, "getenv");

        setlinebuf(stdout);
    }

    return getenv_real(s);
}

次に、そのファイルを共有オブジェクトとしてコンパイルします:

gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc

次に、 LD_PRELOAD を設定します プログラムと一緒にロードする変数:

$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out 
0
1000
2000
3000
4000

運が良ければ、問題は 不運 なしで解決されます 副作用。

LD_PRELOAD を設定できます 必要に応じて、シェル内のライブラリを指定するか、システム全体でそのライブラリを指定することさえできます (絶対に NOT 推奨) /etc/ld.so.preload .


ティーへの配管を検討しましたか?

./program | tee a.txt

ただし、「プログラム」が完了するまで標準出力に何も書き込まないと、tee でさえ機能しません。したがって、有効性はプログラムの動作に大きく依存します。


既存のプログラムの動作を変更しようとしている場合は、stdbuf (明らかにバージョン 7.5 以降の coreutils の一部) を試してください。

これは stdout を 1 行までバッファリングします:

stdbuf -oL command > output

これにより、stdout バッファリングが完全に無効になります:

stdbuf -o0 command > output


Linux
  1. Linux I / O(入力/出力)リダイレクトの仕組みの基本を学ぶ

  2. Linux/Unixでの入力/出力リダイレクト

  3. プログラムの出力をZipファイルにリダイレクトする方法は??

  1. Stdoutに出力し、同時にGrepをファイルに出力しますか?

  2. 標準出力を閉じる(>&-)?

  3. イオリダイレクションとヘッドコマンド?

  1. 出力をファイルと標準出力にリダイレクトする方法

  2. ファイルの 2 列目を出力する

  3. すべての出力を Bash のファイルにリダイレクトします