bashスクリプトの実行中に、出力をファイルに強制的にフラッシュする


90

次のコマンドを使用してcrontabによって毎日呼び出される小さなスクリプトがあります。

/homedir/MyScript &> some_log.log

このメソッドの問題は、some_log.logがMyScriptの終了後にのみ作成されることです。プログラムの実行中にプログラムの出力をファイルにフラッシュしたいので、次のようなことができます

tail -f some_log.log

進捗状況などを追跡します。


小さなスクリプトが正確に実行することの説明(または可能であればコード)が必要になります...–
ChristopheD

7
Pythonスクリプトのバッファを解除するには、「python-u」を使用できます。perlスクリプトのバッファを解除するには、以下のGregHewgillの返信を参照してください。以下のように...
Eloici

スクリプトを編集できる場合は、通常、スクリプト内で出力バッファーを明示的にフラッシュできますsys.stdout.flush()。たとえば、Pythonで。
drevicko 2017

回答:


28

bash自体が実際にログファイルに出力を書き込むことはありません。代わりに、スクリプトの一部として呼び出すコマンドは、それぞれ個別に出力を書き込み、必要に応じてフラッシュします。したがって、あなたの質問は、bashスクリプト内のコマンドを強制的にフラッシュする方法であり、それはそれらが何であるかによって異なります。


25
私はこの答えを本当に理解していません。
アルフォンソサンティアゴ

3
標準出力がこのように動作する理由については、stackoverflow.com / a / 13933741/282728を確認してください。短いバージョン-デフォルトでは、ファイルにリダイレクトされると、stdoutは完全にバッファリングされます。フラッシュ後にのみファイルに書き込まれます。Stderrはそうではありません—すべての '\ n'の後に書かれています。1つの解決策は、以下のuser3258569が推奨する「script」コマンドを使用して、行が終了するたびにstdoutをフラッシュすることです。
アレックス

2
明白なことを述べ、10年後ですが、これはコメントであり、答えではなく、受け入れられる答えであってはなりません。
RealHandy

87

私はここでこれに対する解決策を見つけました。OPの例を使用して、基本的に実行します

stdbuf -oL /homedir/MyScript &> some_log.log

その後、出力の各行の後にバッファがフラッシュされます。私はよくこれを組み合わせnohupて、リモートマシンで長いジョブを実行します。

stdbuf -oL nohup /homedir/MyScript &> some_log.log

これにより、ログアウト時にプロセスがキャンセルされることはありません。


1
のドキュメントへのリンクを追加できますstdbufか?このコメントに基づくと、一部のディストリビューションでは利用できないようです。明確にできますか?
モニカの訴訟に資金

1
stdbuf -oは、stdoutバッファリングを調整します。他のオプションは、stdinおよびstderrの-iおよび-eです。Lはラインバッファリングを設定します。バッファサイズを指定することもできます。バッファリングしない場合は0を指定することもできます。
Seppo Enarvi 2016

5
そのリンクは利用できなくなりました。
john-jones 2017年

2
@NicHartley:stdbufGNU coreutilsの一部であり、ドキュメントはgnu.org
Thor

場合、それは誰も、助けを使用し export -f my_function、その後stdbuf -oL bash -c "my_function -args"、スクリプトの代わりに関数を実行する必要がある場合
匿名

29
script -c <PROGRAM> -f OUTPUT.txt

キーは-fです。男のスクリプトからの引用:

-f, --flush
     Flush output after each write.  This is nice for telecooperation: one person
     does 'mkfifo foo; script -f foo', and another can supervise real-time what is
     being done using 'cat foo'.

バックグラウンドで実行:

nohup script -c <PROGRAM> -f OUTPUT.txt

うわー!で機能するソリューションbusybox!(私のシェルはその後フリーズしますが、何でも)
Victor Sergienko 2018

9

を使用teeして、フラッシュせずにファイルに書き込むことができます。

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null

2
これは、少なくとも私のUbuntu 18.04環境では、出力をバッファリングします。最終的にはどちらの方法でも内容がファイルに書き込まれますが、OPはファイルの書き込みが完了する前に進行状況をより正確に監視できる方法を求めていると思います。この方法では出力リダイレクト以上のことはできません。します。
mltsy 2018

3

これはの機能ではありません。bashシェルが行うのは、問題のファイルを開いてから、スクリプトの標準出力としてファイル記述子を渡すことだけです。あなたがする必要があるのは、あなたが現在よりも頻繁にスクリプトから出力がフラッシュされることを確認することです。

たとえばPerlでは、これは次のように設定することで実現できます。

$| = 1;

詳細については、perlvarを参照してください。


2

出力のバッファリングは、プログラムの/homedir/MyScript実装方法によって異なります。出力がバッファリングされていることに気付いた場合は、実装でそれを強制する必要があります。たとえば、Pythonプログラムの場合はsys.stdout.flush()を使用し、Cプログラムの場合はfflush(stdout)を使用します。


2

これは役に立ちますか?

tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq 

これにより、stdbufユーティリティを使用してaccess.logからの一意のエントリがすぐに表示されます


唯一の問題は、stdbufが新しいディストリビューションでは利用できない古いユーティリティのように見えることです。
Ondraジシュカ

..また私のbusyboxで:(
Campa

実際、私はstdbuf現在Ubuntuで利用できますが、どこで入手したかわかりません。
Ondraジシュカ

Centos 7.5にstdbufがあります
最大

1
Ubuntu 18.04では、stdbufcoreutilus(で見つかりましたapt-file search /usr/bin/stdbuf)の一部です。
rmano 2018年

1

ここで問題を見つけのは、スクリプトから実行するプログラムがジョブを終了するのを待たなければならないということです。
スクリプトでプログラムをバックグラウンドで実行する場合は、さらに何かを試すことができます。

一般に、sync終了する前にを呼び出すと、ファイルシステムバッファをフラッシュでき、少し役立つ場合があります。

スクリプトでいくつかのプログラムをバックグラウンド&)で開始した場合、スクリプトを終了する前に、プログラムが終了するのを待つことができます。それがどのように機能するかについての考えを持っているためにあなたは以下を見ることができます

#!/bin/bash
#... some stuffs ...
program_1 &          # here you start a program 1 in background
PID_PROGRAM_1=${!}   # here you remember its PID
#... some other stuffs ... 
program_2 &          # here you start a program 2 in background
wait ${!}            # You wait it finish not really useful here
#... some other stuffs ... 
daemon_1 &           # We will not wait it will finish
program_3 &          # here you start a program 1 in background
PID_PROGRAM_3=${!}   # here you remember its PID
#... last other stuffs ... 
sync
wait $PID_PROGRAM_1
wait $PID_PROGRAM_3  # program 2 is just ended
# ...

数字waitだけでなく仕事でも機能するのでPID、スクリプトの最後に怠惰​​な解決策を置く必要があります

for job in `jobs -p`
do
   wait $job 
done

より難しいのは、バックグラウンドで他の何かを実行する何かを実行する場合、すべてのプロセスの終了を検索して待機する必要があるためです(その場合)。たとえば、デーモンを実行する場合は、おそらくそうではありません。それが終了するのを待つ:-)。

注意:

  • wait $ {!}は、「最後のバックグラウンドプロセスが完了するまで待つ」ことを意味し$!ます。ここで、は最後のバックグラウンドプロセスのPIDです。したがって、wait ${!}直後に配置することは、バックグラウンドで送信せずにprogram_2 &直接実行するprogram_2ことと同じです。&

  • の助けからwait

    Syntax    
        wait [n ...]
    Key  
        n A process ID or a job specification
    

1

おかげで@user3258569、スクリプトはおそらくで動作する唯一のものbusyboxです!

しかし、その後、シェルは私にとって凍っていました。原因を探すと、スクリプトのマニュアルページに「非対話型シェルでは使用しないでください」という大きな赤い警告が見つかりました。

script主にインタラクティブなターミナルセッション用に設計されています。stdinがターミナルではない場合(例:)echo foo | script、スクリプトセッション内のインタラクティブシェルがEOFを見逃しscript、セッションをいつ閉じるかわからないため、セッションがハングする可能性があります。詳細については、「注意」セクションを参照してください。

本当。script -c "make_hay" -f /dev/null | grep "needle"私のために殻を凍らせていました。

警告に反して、echo "make_hay" | scriptEOFを通過すると思ったので試してみました

echo "make_hay; exit" | script -f /dev/null | grep 'needle'

そしてそれはうまくいきました!

manページの警告に注意してください。これはうまくいかないかもしれません。


0

stdbufの代わりにawk '{print} END {fflush()}' 、これを行うためのbashが組み込まれていればいいのですが。通常は必要ありませんが、古いバージョンではファイル記述子にbash同期のバグがある可能性があります。


-2

それがうまくいくかどうかはわかりませんが、電話するのはsyncどうですか?


1
syncは低レベルのファイルシステム操作であり、アプリケーションレベルでのバッファリングされた出力とは関係ありません。
Greg Hewgill

2
sync必要に応じて、ダーティなファイルシステムバッファを物理ストレージに書き込みます。これはOSの内部です。OS上で実行されているアプリケーションは、ディスクブロックが物理ストレージに書き込まれているかどうかに関係なく、常にファイルシステムの一貫したビューを確認します。元の質問の場合、アプリケーション(スクリプト)はおそらくアプリケーション内部のバッファーに出力をバッファリングしており、OSは出力が実際にstdoutに書き込まれることを(まだ)認識していません。したがって、架空の「同期」タイプの操作では、スクリプトに「到達」してデータを引き出すことはできません。
Greg Hewgill

-2

を使用したMacOSXのバックグラウンドプロセスでこの問題が発生しましたStartupItems。これが私がそれを解決する方法です:

私が作るsudo ps auxと、それmytoolが起動していることがわかります。

Mac OS Xがシャットダウンしたときに(バッファリングのために)mytool出力がsedコマンドに転送されないことがわかりました。ただし、を実行するsudo killall mytoolmytool、出力がsedコマンドに転送されます。したがって、Mac OSXがシャットダウンしたときに実行されるstopケースを追加しましたStartupItems

start)
    if [ -x /sw/sbin/mytool ]; then
      # run the daemon
      ConsoleMessage "Starting mytool"
      (mytool | sed .... >> myfile.txt) & 
    fi
    ;;
stop)
    ConsoleMessage "Killing mytool"
    killall mytool
    ;;

これは、ご使用の環境に非常に固有であるため、Freemanの良い答えではありません。OPは、出力を強制終了するのではなく、監視することを望んでいます。
灰色

-3

好むと好まざるとにかかわらず、これがリダイレクトの仕組みです。

あなたの場合、スクリプトの出力(スクリプトが終了したことを意味します)はそのファイルにリダイレクトされます。

あなたがしたいのは、スクリプトにそれらのリダイレクトを追加することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.