1

我正在编写一个简单的 Bash 脚本,它只是调用 HadnBrakeCli 来渲染视频。我还实现了一个简单的队列选项:队列文件只存储它必须调用以启动渲染的行命令。所以我写了一个while循环来一次读取一行,eval $line 并重复直到文件结束。

    if [[ ${QUEUE_MODE} = 'RUN' ]]; then
    QUEUE_LEN=`cat ${CONFIG_DIR}/queue | wc -l`
    QUEUE_POS='1'
    printf "Queue lenght:\t ${QUEUE_LEN}\n"

    while IFS= read line; do
        echo "--Running render ${QUEUE_POS} on ${QUEUE_LEN}..."
        echo "++" && echo "$line" && echo "++"
        eval "${line}"
        tail -n +2 "${CONFIG_DIR}/queue" > "${CONFIG_DIR}/queue.tmp" && mv "${CONFIG_DIR}/queue.tmp" "${CONFIG_DIR}/queue"
        echo "--Render ended"
        QUEUE_POS=`expr $QUEUE_POS + 1`
    done < "${CONFIG_DIR}/queue"
    exit 0

问题是任何命令都可以使循环正常工作(空行,回显“测试”......),但是一旦加载了正确的渲染,它就会正确启动并完成,但循环也存在。

我是新手,所以我尝试了一些小改动来看看我得到了什么效果,但没有改变结果。我评论了命令,或者我在 while 循环中tail -n +2 "${CONFIG_DIR}/queue" > "${CONFIG_DIR}/queue.tmp" && mv "${CONFIG_DIR}/queue.tmp" "${CONFIG_DIR}/queue"添加/删除了,或者删除了in命令。对不起,如果这个问题是微不足道的,但我真的错过了它如何工作的一些主要部分,所以我什至不知道如何搜索解决方案。IFS=-rread

我将在队列文件中放置一个通用渲染示例。 HandBrakeCLI -i "/home/andrea/Videos/done/Rap dottor male e mini me.mp4" -o "/hdd/Render/Output/Rap dottor male e mini me.mkv" -e x265 -q 23 --encoder-preset faster --all-audio -E av_aac -6 dpl2 --all-subtitles -x pmode:pools='16' --verbose=0 2>/dev/null

4

1 回答 1

1

HandBrakeCLIread line从标准输入读取,这会在看到它之前窃取队列文件的其余部分。我最喜欢的解决方案是将文件传递给标准输入以外的其他内容,例如文件描述符#3:

...
while IFS= read line <&3; do    # The <&3 makes it read from FD #3
    ...
done 3< "${CONFIG_DIR}/queue"   # The 3< redirects the file into FD #3

避免该问题的另一种方法是将输入重定向到 HandBrakeCLI 命令:

...
eval "${line}" </dev/null
...

在 BashFAQ #89 中有更多关于此的信息:我正在逐行读取文件并运行 ssh 或 ffmpeg,只有第一行得到处理!

另外,我不确定我是否相信您在tail执行队列文件时用于从队列文件中删除行的方式。我不确定这是否真的错了,它对我来说只是看起来很脆弱。此外,我建议使用小写或混合大小写的变量名称,因为有一堆全大写的名称具有特殊含义,并且错误地重新使用其中一个可能会产生奇怪的后果。最后,我建议您通过shellcheck.net运行您的脚本,因为它会提出一些其他好的建议。

[顺便说一句,这个问题是“Bash script do loop exiting early”的副本,但没有任何赞成或接受的答案。]

于 2021-01-13T21:05:22.167 回答