Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash脚本仍在运行时强制刷新输出到文件_Bash_File_Flush - Fatal编程技术网

在bash脚本仍在运行时强制刷新输出到文件

在bash脚本仍在运行时强制刷新输出到文件,bash,file,flush,Bash,File,Flush,我有一个小脚本,crontab每天使用以下命令调用它: /homedir/MyScript &> some_log.log 此方法的问题是,某些_log.log仅在MyScript完成后创建。我想在程序运行时将程序的输出刷新到文件中,以便执行以下操作 tail -f some_log.log 并跟踪进度等。这不是bash的功能,因为shell所做的只是打开相关文件,然后将文件描述符作为脚本的标准输出传递。您需要做的是确保从脚本中刷新输出的频率高于当前的频率 例如,在Perl中,

我有一个小脚本,crontab每天使用以下命令调用它:

/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'