【问题标题】:Shell script: Redirect output of program to changing filesShell脚本:将程序的输出重定向到更改的文件
【发布时间】:2018-06-05 13:31:57
【问题描述】:

我的目标:

我想根据程序的运行时间将我的程序foostdout 输出重定向到不断变化的输出文件。

程序foo 本身正在bsd 套接字上侦听到达的数据包并显示其中包含的信息。
所以本质上,在运行程序foo 10 分钟后,我希望有

stdout 输出
  • 文件中的第一分钟bar_0.dat
  • 文件bar_1.dat内的第二分钟
  • 文件bar_9.dat内的第10分钟

是否可以在 shell 脚本中实现这一点,如果可以,我该如何实现?

到目前为止我所管理的:

我只管理了这个解决方案,程序在每分钟后重新启动,并重定向到一个新的输出文件:

#!/bin/bash
for i in {0..9}
do
  timeout 60s foo > "bar_${i}.dat"
done

但是,我希望程序 foo 持续运行,而不必重新启动它,因为我已经意识到我丢失了一些到达的数据包(运行实例之间有 20-30 毫秒的间隔) .

【问题讨论】:

    标签: linux bash shell redirect stdout


    【解决方案1】:

    让程序写入命名管道 (fifo),然后从该管道获取输出并将其放入文件中。在此处的示例中,我在后台启动循环,然后立即开始写入命名管道:

    mkfifo thepipe
    
    for (( i = 0; i < 10; ++i )); do
        timeout 60 cat thepipe >"bar_$i.dat"
    done &
    
    foo >thepipe
    rm -f thepipe
    

    或者,使用进程替换:

    foo > >( 
        for (( i = 0; i < 10; ++i )); do
            timeout 60 cat >"bar_$i.dat"
        done
    )
    

    【讨论】:

    • 非常感谢您的建议!第二种解决方案(流程替换)完全按照我的意图工作(只要我有必要的声誉,+1)。第一个解决方案(管道)用第一分钟的stdout 填充第一个文件,但是只创建了以下文件,但没有输入数据。
    • 在尝试了所有建议的答案之后,您使用过程替代的解决方案是我最喜欢的解决方案。您能否删除或更新管道解决方案(目前无法正常工作,请参阅我之前的评论)?然后我会将接受切换为您的答案。非常感谢。
    • @oh.dae.su 谢谢,最后这很容易解决。它现在应该可以工作了。
    • 感谢您的更新。不幸的是,管道解决方案仍然只能在bar_0.dat 完成之前有效。然后行为从运行更改为运行。有时它会因cat: thepipe: No such file or Directory 而崩溃。
    【解决方案2】:

    如果 foo 正在生成文本输出,您可能会得到以下结果:

    #!/bin/bash
    
    stamp=0
    i=0
    redirect() {
            if test "$(date +%s)" -gt "$((stamp + 60))"; then
                    stamp=$(date +%s)
                    exec > "bar_$((i++)).dat"
            fi
    }
    redirect
    ./foo | while read line; do
            echo "$line"
            redirect
    done
    

    如果 foo 不产生文本输出,您可能需要编写 foo 以便它接受外部输入(例如,信号)并自行重定向输出。或者,您可能只想使用 logrotate。

    【讨论】:

    • 完美运行。非常感谢!只要我有必要的声誉+1! ;-)
    • 如果它包含反斜杠,这将破坏输出。它还会在行的开头和结尾去除空格。
    【解决方案3】:

    您可以使用无限循环和日期/时间戳作为文件名:

    while true
    do
        #This date/time stamp is month_day_hour_minute all numbers
        filename="bar_$(date "+%m_%d_%H_%M").dat"
        foo > $filename 2>> error_log
        sleep 60
    done
    

    还为任何错误消息添加了错误日志。不确定您的程序如何处理stderr

    【讨论】:

    • 感谢您的建议。但是,由于 foo 本身在无限循环中运行,您的代码会导致 stdout 被写入单个文件,只是永远不会到达带有 sleep 60 的代码行。
    • @oh.dae.su 呸。我相信我看错了你的描述=D。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2014-11-08
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多