【发布时间】:2017-07-25 13:04:05
【问题描述】:
我使用一个命令来解析某些帧的视频文件,并在找到时返回它们的时间码。目前,我必须执行命令,等待,直到打印到 stdout 的值到达所需位置,然后使用 Ctrl+C 中止执行。
由于我必须观察该过程并在适当的时候中止执行以获取所需的信息,我想,我可以通过创建一个 bash 脚本在某种程度上自动执行此操作。
我不确定是否可以在 bash 中完成,因为我不完全知道,如何中止与它写入标准输出的值相关的执行。
命令的输出看起来像
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"
这似乎都导致命令被执行,直到它完成,然后循环的其余部分被处理。但我想在命令执行时评估输出,并根据输出中断执行。
附加信息
该命令无法在流中的某个点停止。它解析整个文件并给出结果,除非发出停止信号。这是我的第一枪。
该命令的执行时间很长,因为我解析的文件约为 2GB。由于我不需要文件的所有帧,而只需要给定时间码附近的几个帧,因此在完成之前我从不让它执行。
命令的输出因文件而异,因此我无法找到确切的值。如果我知道确切的值,我可能就不必寻找它了。
目标时间码 - 在示例中由“-gt 30”指定 - 对于我必须解析的每个文件都是不同的,因此一旦脚本工作,我必须将其放入命令行参数中。我还必须确保返回的值超过执行的最后一个值,但大约是最后 5 个值。对于这两个我已经有想法了。
我完全被那个卡住了,甚至不知道要谷歌搜索什么。
感谢您的意见!
曼努埃尔
通过 PSkocik 和 Kyle Burton 的回答,我能够将建议的解决方案集成到我的脚本中。它不起作用,我不明白,为什么。
这里是完整的脚本,包括提供输出的外部命令:
#!/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 停止脚本。
感谢凯尔为此付出的巨大努力。我永远不会得出这样的结论。我将 ffprobe 的命令行更改为您的建议
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 命令的原始输出如下所示
1|0.000000
0|0.040000
0|0.080000
0|0.120000
0|0.160000
0|0.200000
(...)
行首的 0 表示:这不是关键帧。 行首的 1 表示:这是一个关键帧。
该脚本旨在仅提供视频文件特定时间码周围的关键帧。您更改命令的方式现在提供了视频文件的所有帧,这使得结果输出无用。必须过滤掉所有以零开头的行。
由于我不完全理解,为什么这不适用于 sed,我只能尝试通过尝试和错误来找到解决方案,以便使用不同的工具来过滤输出。但如果过滤本身导致问题,我们可能在这里碰壁了。
【问题讨论】:
-
我想知道读取是否有效。如果您将
echo $tc更改为echo tc=$tc,您会看到类似tc=的行吗?您可以运行ffprobe <<with those args>> | sed -ne "s/^1|//p" | head并分享该输出吗?我现在想知道为什么读取失败以及 ffprobe 是否正在打印行 - 所以我试图缩小错误可能出现的位置。 -
将
echo $tc更改为echo "Read: $tc",但没有打印任何内容。# ffprobe Input.avi -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"打印0.040000 5.040000 10.040000 15.040000 18.060000 21.980000 26.980000 -
啊!
ffprobe的输出是空格而不是换行符吗?让我调整我的示例,看看我是否可以将空格转换为换行符并更接近您的需要。我更新了答案以包括使用tr- 试试看? -
已经想到你可能会这样做。返回值已被评论系统放入一行。每个值都在一行中。尝试了您的更新,但没有任何改变。当使用包含函数生成值的版本时,我会取回这些值。
-
好的,这就是我认为当前的事实是关于
ffprobe:它每行发出一个浮点数,我们似乎无法逐行读取这些数字。我们确定它不会超过标准错误?我们如何才能将事情缩小到 ffprobe 正在输出什么以及它是如何输出的?如果您要获取上面复制的输出并将其放入文本文件中,那么读取循环将起作用,那么是什么使它无法正常工作呢?你是否可以在某个地方发布一个(小)视频文件,我可以测试这个脚本和ffprobe我自己?
标签: linux bash shell stdout execution