次のコマンドを使用してcrontabによって毎日呼び出される小さなスクリプトがあります。
/homedir/MyScript &> some_log.log
このメソッドの問題は、some_log.logがMyScriptの終了後にのみ作成されることです。実行中にプログラムの出力をファイルにフラッシュして、次のようなことができるようにします
tail -f some_log.log
進行状況などを追跡します.
bash自体が実際にログファイルに出力を書き込むことはありません。代わりに、スクリプトの一部として呼び出されるコマンドは、出力を書き込み、必要に応じてフラッシュします。したがって、あなたの質問は、bashスクリプト内のコマンドを強制的にフラッシュする方法です。それは、それらが何であるかに依存します。
これに対する解決策を見つけました here 。 OPの例を使用して、基本的に実行します
stdbuf -oL /homedir/MyScript &> some_log.log
そして、出力の各行の後にバッファーがフラッシュされます。私はこれをNohup
と組み合わせて、リモートマシンで長いジョブを実行することがよくあります。
stdbuf -oL Nohup /homedir/MyScript &> some_log.log
この方法では、ログアウト時にプロセスがキャンセルされません。
script -c <PROGRAM> -f OUTPUT.txt
キーは-fです。 manスクリプトからの引用:
-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
tee
を使用して、フラッシュする必要なくファイルに書き込むことができます。
/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
これはbash
の機能ではありません。シェルは問題のファイルを開き、ファイル記述子をスクリプトの標準出力として渡すだけです。あなたがする必要があるのは、出力がフラッシュされることを確認することですスクリプトから現在よりも頻繁に。
たとえば、Perlでは、これを次のように設定することで実現できます。
$| = 1;
これについての詳細は perlvar をご覧ください。
これは役に立ちますか?
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
これにより、access.logから一意のエントリがすぐに表示されます
http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html
出力のバッファリングは、プログラム/homedir/MyScript
が実装されています。出力がバッファリングされていることがわかった場合は、実装でそれを強制する必要があります。たとえば、pythonプログラムの場合はsys.stdout.flush()を使用し、Cプログラムの場合はfflush(stdout)を使用します。
ありがとう@user3258569
、スクリプトは、おそらくbusybox
で機能する唯一のものです!
しかし、シェルはその後、私のために凍結していました。原因を探して、私はこれらの大きな赤い警告を「非対話式シェルで使用しないでください」と見つけました スクリプトマニュアルページ :
script
は、主にインタラクティブなターミナルセッション用に設計されています。 stdinが端末ではない場合(例:echo foo | script
)、スクリプトセッション内のインタラクティブシェルが[〜#〜] eof [〜#〜]およびscript
には、セッションを閉じるタイミングがわかりません。詳細については、[〜#〜] notes [〜#〜]セクションを参照してください。
本当です。 script -c "make_hay" -f /dev/null | grep "needle"
は私のためにシェルを凍結していました。
警告に反して、私はecho "make_hay" | script
EOFに合格するので、試しました
echo "make_hay; exit" | script -f /dev/null | grep 'needle'
そしてそれは働いた!
Manページの警告に注意してください。これはあなたのために働かないかもしれません。
見つけた方法 ここ 問題は、スクリプトから実行するプログラムがジョブを終了するまで待つ必要があることです。
スクリプト内でbackgroundでプログラムを実行すると、さらに試行することができます。
一般に、終了する前にsync
を呼び出すと、ファイルシステムバッファーをフラッシュでき、少し役立ちます。
スクリプトでbackground(&
)でいくつかのプログラムを起動する場合、 wait スクリプトを終了する前に終了すること。それがどのように機能するかについてのアイデアを得るには、以下を見ることができます
#!/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
すべてのchildプロセスの終了を検索して待機する必要があるため(バックグラウンドで何か他の何かを実行する場合)、より困難な状況です:forたとえば、daemonを実行すると、おそらく終了するのを待つことはできません:-)。
注意:
wait $ {!}は、「最後のバックグラウンドプロセスが完了するまで待つ」ことを意味します。$!
は、最後のバックグラウンドプロセスのPIDです。 wait ${!}
の直後にprogram_2 &
を置くことは、program_2
でバックグラウンドで送信せずに&
を直接実行することと同等です。
wait
の助けから:
Syntax
wait [n ...]
Key
n A process ID or a job specification
stdbufの代替はawk '{print} END {fflush()}'
です。これを行うための組み込みのbashがあればいいのにと思います。通常は必要ありませんが、古いバージョンではファイル記述子にbash同期バグがある可能性があります。