我有一个小脚本,每天由crontab使用以下命令调用:
/homedir/MyScript &> some_log.log
此方法的问题在于,仅在MyScript完成后才创建some_log.log。我想在程序运行时将程序的输出刷新到文件中,以便执行以下操作
tail -f some_log.log
并跟踪进度等。
我有一个小脚本,每天由crontab使用以下命令调用:
/homedir/MyScript &> some_log.log
此方法的问题在于,仅在MyScript完成后才创建some_log.log。我想在程序运行时将程序的输出刷新到文件中,以便执行以下操作
tail -f some_log.log
并跟踪进度等。
sys.stdout.flush()
。
Answers:
bash本身实际上不会将任何输出写入日志文件。相反,它作为脚本的一部分调用的命令将在需要时分别写入输出并刷新。因此,您的问题实际上是如何强制刷新bash脚本中的命令,这取决于它们是什么。
我在这里找到了解决方案。使用OP的示例,您基本上可以运行
stdbuf -oL /homedir/MyScript &> some_log.log
然后在输出的每一行之后刷新缓冲区。我经常将其与nohup
在远程计算机上运行长时间作业结合在一起。
stdbuf -oL nohup /homedir/MyScript &> some_log.log
这样,您的进程在注销时不会被取消。
stdbuf
是GNU的coreutils的一部分,文档可以在gnu.org发现
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
!(之后我的外壳会冻结,但是无论如何)
stdbuf
在Ubuntu中可用,不确定我从哪里得到的。
stdbuf
是的一部分coreutilus
(位于apt-file search /usr/bin/stdbuf
)。
只是如何发现这里的问题是,你必须等待那您从脚本运行的程序完成自己的工作。
如果您在脚本中在后台运行程序,则可以尝试更多操作。
通常,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
如果您运行在后台运行其他内容的某事,则更加困难,因为您必须搜索并等待(如果是这种情况)所有子进程的结束:例如,如果您运行一个守护程序,可能不是这种情况等待它完成:-)。
注意:
等待$ {!}表示“等待直到最后一个后台进程完成”,其中$!
是最后一个后台进程的PID。所以放在wait ${!}
后面program_2 &
就等于直接执行program_2
而无需在后台发送&
来自wait
:
Syntax
wait [n ...]
Key
n A process ID or a job specification
谢谢@user3258569
,脚本可能是唯一起作用的东西busybox
!
不过,壳对我来说冻结了。寻找原因,我在脚本手册页中找到了这些大的红色警告“请勿在非交互式外壳中使用” :
script
主要用于交互式终端会话。如果stdin不是终端(例如:)echo foo | script
,则会话可以挂起,因为脚本会话中的交互式shell会错过EOF,script
并且不知道何时关闭会话。有关更多信息,请参见“注意”部分。
真正。script -c "make_hay" -f /dev/null | grep "needle"
为我冻结了外壳。
反对警告,我以为会echo "make_hay" | script
通过EOF,所以我尝试了
echo "make_hay; exit" | script -f /dev/null | grep 'needle'
而且有效!
请注意手册页中的警告。这可能对您不起作用。
我不知道是否可行,但是打电话sync
呢?
sync
是低级文件系统操作,与应用程序级别的缓冲输出无关。
sync
如有必要,将所有脏文件系统缓冲区写入物理存储。这是操作系统内部的;无论磁盘块是否已写入物理存储,运行在OS之上的应用程序始终会看到文件系统的一致视图。对于最初的问题,应用程序(脚本)可能正在将输出缓冲在应用程序内部的缓冲区中,并且操作系统甚至都不知道(但)输出实际上已注定要写入stdout。因此,假设的“同步”类型操作将无法“进入”脚本并提取数据。
我在Mac OS X中使用时遇到了后台进程的问题StartupItems
。这是我解决的方法:
如果我确定sudo ps aux
可以看到mytool
启动了。
我发现(由于缓冲)Mac OS X关闭时,mytool
永远不会将输出传输到sed
命令。但是,如果执行sudo killall mytool
,则将mytool
输出传输到sed
命令。因此,我向Mac OS X关闭时执行的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
;;
不管喜欢与否,这就是重定向的原理。
在您的情况下,脚本的输出(意味着脚本已完成)被重定向到该文件。
您要做的是在脚本中添加这些重定向。