当bash脚本仍在运行时强制将输出刷新到文件
我有一个小脚本,每天通过crontab使用以下命令调用:
/homedir/MyScript &> some_log.log
这个方法的问题是some_log.log只是在MyScript完成之后才创build的。 我想在运行的时候把程序的输出清空到文件中,这样我就可以做类似的事情了
tail -f some_log.log
并跟踪进度等
bash本身永远不会写任何输出到你的日志文件。 相反,它作为脚本的一部分调用的命令将分别写入输出和刷新,只要他们喜欢它。 所以你的问题是如何强制在bash脚本内的命令刷新,这取决于它们是什么。
我在这里find了一个解决scheme。 使用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
的function,因为所有的shell都是打开有问题的文件,然后将文件描述符作为脚本的标准输出。 你需要做的是确保输出比你现在更频繁地从你的脚本刷新。
在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
这里发现的问题是,你必须等待你的脚本运行的程序完成他们的工作。
如果你的脚本在后台运行程序,你可以尝试更多的东西。
一般来说,在退出之前调用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
号码,一个懒惰的解决scheme应该是放在脚本的末尾
for job in `jobs -p` do wait $job done
如果你运行一些在后台运行的东西,更困难的是你必须search并等待(如果是这样的话)所有子进程的结束:例如,如果你运行一个守护进程,可能情况并非如此等待它完成:-)。
注意:
-
等待$ {!}的意思是“等到最后的后台进程完成”
$!
是最后一个后台进程的PID。 因此,在program_2 &
之后wait ${!}
等于直接执行program_2
而不用在后台发送&
-
从
wait
的帮助:Syntax wait [n ...] Key n A process ID or a job specification
缓冲输出取决于你的程序/homedir/MyScript
是如何实现的。 如果你发现输出缓冲,你必须强制执行。 例如,如果是python程序,请使用sys.stdout.flush();如果是C程序,请使用fflush(stdout)。
我不知道这是否会起作用,但是如何调用sync
?
我在使用StartupItems
Mac OS X中使用后台进程时遇到了这个问题。 这是我如何解决它:
如果我使用sudo ps aux
我可以看到mytool
已经启动了。
当Mac OS Xclosures时,我发现(由于缓冲) mytool
决不会将输出传输到sed
命令。 但是,如果我执行sudo killall mytool
,则mytool
会将输出传输到sed
命令。 因此,我在Mac OS Xclosures时执行的StartupItems
中添加了一个stop
事件:
start) if [ -x /sw/sbin/mytool ]; then # run the daemon ConsoleMessage "Starting mytool" (mytool | sed .... >> myfile.txt) & fi ;; stop) ConsoleMessage "Killing mytool" killall mytool ;;
以及是否这个redirect是如何工作的。
在你的情况下,你的脚本的输出(意思是脚本已经完成)redirect到该文件。
你想要做的是在脚本中添加这些redirect。