Bash While循环逐行读取某行上的文件出口



我正在编写一个简单的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

问题是,任何命令都会使循环正常工作(空行、echo"test"…(,但一旦加载了正确的渲染,它就会正确启动并完成,但循环也存在。

我是一个新手,所以我尝试了一些小的改变,看看我得到了什么效果,但没有改变结果。我对命令tail -n +2 "${CONFIG_DIR}/queue" > "${CONFIG_DIR}/queue.tmp" && mv "${CONFIG_DIR}/queue.tmp" "${CONFIG_DIR}/queue"进行了注释,或者在while循环中添加/删除了IFS=,或者在read命令中删除了-r。如果这个问题很琐碎,我很抱歉,但我真的错过了它如何工作的一些重要部分,所以我甚至不知道如何搜索解决方案。

我将在队列文件中放入一个常规渲染的示例。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

HandBrakeCLI从标准输入读取,在read 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 existing early"的重复,但没有任何支持或接受的答案。]

最新更新