在bash脚本仍在运行时强制刷新输出到文件
我有一个小脚本,crontab每天使用以下命令调用它:在bash脚本仍在运行时强制刷新输出到文件,bash,file,flush,Bash,File,Flush,我有一个小脚本,crontab每天使用以下命令调用它: /homedir/MyScript &> some_log.log 此方法的问题是,某些_log.log仅在MyScript完成后创建。我想在程序运行时将程序的输出刷新到文件中,以便执行以下操作 tail -f some_log.log 并跟踪进度等。这不是bash的功能,因为shell所做的只是打开相关文件,然后将文件描述符作为脚本的标准输出传递。您需要做的是确保从脚本中刷新输出的频率高于当前的频率 例如,在Perl中,
/homedir/MyScript &> some_log.log
此方法的问题是,某些_log.log仅在MyScript完成后创建。我想在程序运行时将程序的输出刷新到文件中,以便执行以下操作
tail -f some_log.log
并跟踪进度等。这不是
bash
的功能,因为shell所做的只是打开相关文件,然后将文件描述符作为脚本的标准输出传递。您需要做的是确保从脚本中刷新输出的频率高于当前的频率
例如,在Perl中,可以通过设置:
$| = 1;
有关这方面的更多信息,请参阅。bash本身永远不会将任何输出写入日志文件。相反,它作为脚本的一部分调用的命令将在需要时分别写入输出和刷新。因此,您的问题实际上是如何强制bash脚本中的命令刷新,这取决于它们是什么。我不知道它是否可以工作,但是调用
sync
怎么样?喜欢与否这就是重定向的工作方式
在您的情况下,脚本的输出(意味着您的脚本已完成)重定向到该文件
您要做的是在脚本中添加这些重定向。我在Mac OS X中使用
StartupItems时遇到了后台进程问题。我就是这样解决的:
如果我使用sudo ps aux
我可以看到mytool
已启动
我发现(由于缓冲),当Mac OS X关闭时,mytool
从不将输出传输到sed
命令。但是,如果执行sudo killall mytool
,则mytool
将输出传输到sed
命令。因此,我在Mac OS X关闭时执行的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
;;
这有帮助吗
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
这将立即使用显示access.log中的唯一条目。您可以使用tee
写入文件,而无需刷新
/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
后台运行:
nohup script -c <PROGRAM> -f OUTPUT.txt
nohup脚本-c-f OUTPUT.txt
刚刚发现的问题是,您必须等待从脚本运行的程序完成其任务。
如果在脚本中,您在后台运行程序,您可以尝试更多内容
通常,在退出之前调用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
,而不在后台发送&
- 借助于:
我找到了解决办法。使用OP的示例,您基本上可以运行
stdbuf -oL /homedir/MyScript &> some_log.log
然后在每行输出之后刷新缓冲区。我经常将它与nohup
结合起来,在远程机器上运行长作业
stdbuf -oL nohup /homedir/MyScript &> some_log.log
这样,您的进程在注销时不会被取消。输出缓冲取决于程序/homedir/MyScript
的实现方式。如果发现输出得到缓冲,则必须在实现中强制执行。例如,如果是python程序,请使用sys.stdout.flush();如果是C程序,请使用fflush(stdout)。谢谢@user3258569
,脚本可能是在busybox
中唯一有效的东西
不过,在那之后,贝壳对我来说已经冻僵了。查找原因时,我发现以下红色大警告“请勿在非交互式Shell中使用”:
脚本
主要用于交互式终端会话。什么时候
stdin不是终端(例如:echo foo | script
),则
会话可以挂起,因为脚本中的交互式shell
会话未命中EOF,script
不知道何时关闭会话。
有关更多信息,请参见注释部分
对<代码>脚本-c“make_hay”-f/dev/null | grep“needle”
正在为我冻结外壳
与警告相反,我认为echo“make_hay”| script
将通过EOF,所以我尝试了
echo "make_hay; exit" | script -f /dev/null | grep 'needle'
成功了
请注意手册页中的警告。这可能不适合您。stdbuf的替代方案是
awk'{print}END{fflush()}'
我希望有一个bash内置来做这件事。
通常情况下,这是不必要的,但对于较旧的版本,文件描述符上可能存在bash同步错误。我们需要对您的小脚本的具体功能进行描述,或者如果可能的话,需要编写代码……要解除对python脚本的缓冲,您可以使用“python-u”。要取消缓冲perl脚本,请参阅下面的Greg Hewgill回复。等等……如果可以编辑脚本,通常可以在脚本中显式地刷新输出缓冲区,例如在python中,使用
sys.stdout.flush()
sync
是一种低级文件系统操作,并且是不可用的
stdbuf -oL /homedir/MyScript &> some_log.log
stdbuf -oL nohup /homedir/MyScript &> some_log.log
echo "make_hay; exit" | script -f /dev/null | grep 'needle'