在bash脚本中执行命令,直到输出超过特定值 [英] execute command in bash script until output exceeds certain value

查看:92
本文介绍了在bash脚本中执行命令,直到输出超过特定值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用一个命令来解析某些帧的视频文件,并在找到时返回它们的时间码.此刻,我必须执行命令,等待,直到打印到stdout的值达到所需的位置,然后使用 Ctrl + C 中止执行.

I use a command which parses video files for certain frames and returning their timecode, when found. At the moment, I have to execute the command, wait, until the values printed to stdout reach the desired position and then abort the execution using Ctrl+C.

由于我必须在适当的时候监视流程并中止执行以获取所需的信息,因此我认为可以通过创建bash脚本在某种程度上实现自动化.

As I have to watch the process and to abort the execution in the right moment to get the information I need, I thought, I could automate this to some degree by creating a bash script.

我不确定,如果可以用bash来完成(我不完全知道),那么如何中止执行与写入stdout的值有关的执行.

I am not certain, if it can be done in bash, as I don't exactly know, how to abort the execution in connection with the values it writes to stdout.

命令的输出看起来像

0.040000
5.040000
10.040000
15.040000
18.060000
(...)

我尝试过

until [[ "$timecode" -gt 30 ]]; do
  timecode=$(mycommand)
  sleep 0.1
done

echo "Result: $timecode"

while [[ "$timecode" -le 30 ]]; do
  timecode=$(mycommand)
  sleep 0.1
done

echo "Result: $timecode"

这似乎都导致命令执行完毕,直到执行完毕,然后再处理循环的其余部分.但是我想在命令执行时评估输出,并根据输出中断执行.

which both seem to result in the command being executed until it finishes and afterwards the rest of the loop is being processed. But I want to evaluate the output while the command executes and break execution depending on the output.

其他信息

该命令无法在流中的特定点处停止.除非发出停止信号,否则它将解析整个文件并给出结果.这是我的第一枪.

The command has no capability to be stopped at a certain point in the stream. It parses the whole file and gives the results unless signalled to stop. This was my first shot.

该命令的执行时间非常长,因为我解析的文件约为2GB.由于我不需要文件的所有帧,而在给定的时间码周围只需要几个帧,因此我永远不会让它执行直到完成.

The execution time of the command is very long as the files I parse are ~2GB. As I don't need all frames of the file but only a few around a given timecode, I never let it execute until it finished.

该命令的输出随文件的不同而不同,因此我无法找到确切的值.如果我知道确切的值,则可能不必寻找它.

The output of the command varies from file to file, so I can't look for an exact value. If I knew the exact value, I probably wouldn't have to look for it.

目标时间代码(在示例中由"-gt 30"指定)对于每个我必须解析的文件都是不同的,因此一旦脚本工作,我就必须将其放入命令行参数中.我还必须确保返回的值比执行的最后一个值大,但要比最后5个值大.对于这两个我已经有了想法.

The destination time code - in the example it is specified by "-gt 30" - is different for every file I will have to parse, so I will have to put this into a command line parameter once the script works. I would also have to make sure to get back more than the last value of the execution but about the last 5 values. For these two I already have Ideas.

我完全被那个人困住了,甚至不知道该去做什么.

I'm totally stuck on that one and have not even an idea what to google for.

谢谢您的输入!

Manuel

有了PSkocik和Kyle Burton的回答,我得以将建议的解决方案集成到我的脚本中.它不起作用,我也看不出来,为什么.

With the answers of PSkocik and Kyle Burton, I was able to integrate the suggested solution into my script. It doesn't work and I don't see, why.

以下是完整的脚本,包括提供输出的外部命令:

Here the complete script including the external command providing the output:

 #!/usr/bin/env bash
 set -eu -o pipefail

 parser () {
   local max="$1"
   local max_int

   max_int="${max%.*}"

   while read tc;
     do
       local tc_int
       tc_int="${tc%.*}"
       echo $tc

       if (( "$tc_int" >= "$max_int" )); then
         echo "Over 30: $tc";
         exec 0>&-
         return 0
       fi

     done
 }

 ffprobe "$1" -hide_banner -select_streams v -show_entries frame=key_frame,best_effort_timestamp_time -of csv=nk=1:p=0:s="|" -v quiet | sed -ne "s/^1|//p" | parser 30

我没有从"echo $ tc"得到任何输出,但是ffprobe正在运行-我可以在顶部看到它.它一直运行到我使用 Ctrl + C 停止脚本为止.

I don't get any output from the "echo $tc" but the ffprobe is running - I can see it in top. It runs until I stop the script using Ctrl+C.

感谢Kyle在此方面所做的巨大努力.我永远不会得出这样的结论.我将ffprobe的命令行更改为您的建议

Thank you Kyle for your big efforts in this. I'd never come to such a conclusion. I changed the commandline of ffprobe to your suggestion

 ffprobe "$1" -hide_banner -select_streams v -show_entries frame=key_frame,best_effort_timestamp_time -of csv=nk=1:p=0:s="|" -v quiet | cut -f2 -d\| | parser 30

现在,当ffprobe运行时,我正在获得结果.但是...您更改命令的方式将返回所有帧,ffprobe会发现所有帧,而不仅是关键帧. ffprobe命令的原始输出看起来像

and now, I'm getting results while ffprobe runs. But... the way you changed the command returns all frames, ffprobe finds and not only the Keyframes. The original output of the ffprobe command looks like

 1|0.000000
 0|0.040000
 0|0.080000
 0|0.120000
 0|0.160000
 0|0.200000
 (...)

该行开头的0表示:这不是关键帧. 该行开头的1表示:这是一个关键帧.

The 0 at the beginning of the line means: this is no keyframe. The 1 at the beginning of the line means: this is a keyframe.

该脚本旨在仅在视频文件的特定时间码附近提供关键帧.现在,您更改命令的方式将提供视频文件的所有帧,从而使结果输出无用.必须对所有从零开始删除的行进行过滤.

The script is intended to provide only the keyframes around a certain timecode of the video file. The way you changed the command, it now provides all frames of the video file what makes the resulting output useless. It has to be filtered for all lines starting with zero to be dropped.

由于我不完全了解,为什么sed无法使用它,所以我只能尝试通过尝试和错误来找到解决方案,以利于使用不同的工具来过滤输出.但是,如果过滤本身导致了问题,那么我们可能在这里遇到了麻烦.

As I don't exactly understand, why this doesn't work with sed, I can only try to find a solution by try and error, facilitating different tools to filter the output. But if the filtering itself causes the problem, we might have hit a wall here.

推荐答案

我的问题的答案终于在PSkocik的帮助下以及Kyle Burton的大力支持下找到了.多亏你们两个!

The answer to my question has finally been found by the help of PSkocik and intense support of Kyle Burton. Thanks to both of you!

我不知道,是否有可能将脚本中执行的命令的输出传递给属于该脚本的函数.这是必要的第一条信息.

I didn't know, that it is possible to pipe the output of commands executed in a script to a function that belongs to the script. This was the first piece of information necessary.

我不知道如何正确评估函数内部的管道信息以及如何从函数内部发出信号,以终止生成值的命令的执行.

And I didn't know, how to evaluate the piped information inside the function properly and how to signal from inside the function, that the execution of the command generating the values should be terminated.

此外,Kyle发现,我通过将原始输出传递给sed进行过滤,并将结果数据传递到脚本内部的函数中,这禁止了脚本按设计运行.我仍然不确定为什么,但是肯定可以.

Additionally, Kyle found, that the filtering I did by piping the original output to sed and the resulting data to the function inside the script prohibited the script to function as designed. I'm still uncertain, why - but it definitively does.

生成输出的原始命令现在已通过管道传递到脚本的内部函数.为了避免sed问题,正在函数内部进行过滤.现在一切都按预期工作,我可以继续完成脚本.

The original command generating the output is now being piped as it is to the internal function of the script. The filtering is being done inside the function to avoid the problem with sed. Now everything works as expected and I can continue completing the script.

这是灵魂的工作代码:

 #!/usr/bin/env bash
 set -eu -o pipefail

 function parser () {
   local max="$1"
   local max_int

   max_int="${max%.*}"

   while read tc;
     do

      #If line is empty, continue
      if [ -z "$tc" ]; then
        continue
      fi

      #If first char is 0 (=non-Index Frame), continue
      local iskey="${tc:0:1}";

      if [ $iskey == "0" ]; then
        continue
      fi

      #Return timecode if intended maximum has been reached
      local val="${tc:2:10}"
      local tc_int
      tc_int="${val%.*}"

      if (( "$tc_int" >= "$max_int" )); then
        echo "First index frame at/after given Timecode: $tc";
        exec 0>&-
        return 0
      fi

     done
 }

 ffprobe "$1" -hide_banner -select_streams v -show_entries frame=key_frame,best_effort_timestamp_time -of csv=nk=1:p=0:s="|" -v quiet | parser "$2"

用法:

 ./script.sh "Name of Movie.avi" 30

其中30表示搜索下一个找到的索引帧并返回的时间码.

where 30 represents the timecode at which the next found index frame is being searched and returned.

这篇关于在bash脚本中执行命令,直到输出超过特定值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆