我正在使用脚本来转码一堆电影,使用的是 HandBrake 的命令行版本。我在这里使用的是经过修改的脚本版本:
https://gist.github.com/ralphcrisostomo/56fc395b1646bd55aeeb2eb442043887
我遇到的问题是,转码在一小部分电影上不可重现地挂起。这伴随着 stderr 上的一个非常具体的错误。
我想要的是 1) 跟踪屏幕上的 stdout(而不是 stderr);2) 监视 stderr 中的错误情况;3) 如果满足错误条件,则终止 HandBrake 进程,记录有问题的文件并转到下一个。
目前转码命令如下:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 2> /dev/null
满足1)。
遵循此处的建议:
我可以成功地 grep 错误流中的相关单词,例如
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -i error)
或者
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 3>&2 2>&1 1>&3- | grep -i "error"
但是,所有这些都会将相关行从 stderr 打印到屏幕上。我不清楚如何使用它来执行特定命令,例如 kill HandBrakeCLI ; echo $ITEM >> err.log
我尝试使用 grep -q 来测试是否匹配成功,如下所示:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 3>&2 2>&1 1>&3- | grep -q "error" && echo "error found" ; echo $ITEM >> failed.txt
但是脚本在遇到错误时会直接退出,而不会转到循环中的下一个项目。
任何帮助都值得感激!
已更新以回答 terdon 的问题:
我还对 HandBrake 调用中的初始 echo "" | 感到好奇。它位于查询顶部引用的原始脚本中,但我也不清楚为什么需要它。我在 MacOS 上运行它。完整脚本是
#!/bin/bash
SOURCE=$1
ENCODER=$2
OPTS=$3
TOTAL=$(find "$SOURCE" \! -name ".*" -type f | wc -l)
CURR=0
DESTINATION="PROCESSED"
ENCODER=${ENCODER:="hw"}
# Create directorys
[[ -d $DESTINATION ]] || mkdir -p $DESTINATION
while IFS= read -d '' -r ITEM
do
RES=`ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of default=nw=1 "$ITEM" | grep 'height*' | cut -c 8-`
FILE=${ITEM##*/}
EXT=${ITEM##*.}
EXT=$(echo $EXT | tr "[:upper:]" "[:lower:]")
OUTPUT="$DESTINATION/${FILE%.*}.$EXT"
# Get the right preset
if [[ "$RES" == "2160" ]] && [[ "$ENCODER" == "hw" ]]
then
PRESET="H.265 Apple VideoToolbox 2160p 4K"
elif [[ "$RES" == "2160" ]] && [[ "$ENCODER" == "sw" ]]
then
PRESET="Fast 2160p60 4K HEVC"
elif [[ "$RES" != "2160" ]] && [[ "$ENCODER" == "hw" ]]
then
PRESET="H.265 Apple VideoToolbox 1080p"
elif [[ "$RES" != "2160" ]] && [[ "$ENCODER" == "sw" ]]
then
PRESET="Fast 1080p30"
fi
echo "Processing" $FILE "using preset" $PRESET
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 2> /dev/null
CURR=$((CURR + 1))
echo "done" $CURR "of"$TOTAL
done< <(find "$SOURCE" \( -iname '*.mp4' -or -iname '*.mov' -or -iname '*.MP4' -or -iname '*.MOV' \) -print0)
更新 061224
根据 markp-fuso 的建议,我修改了调用 HandBrake 的行,如下所示:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -i error && { pkill HandBrakeCLI ; echo $ITEM >> err.log; })
遇到错误时,会将相关错误打印到 stdout,但当前编码完成后,才会执行第二部分(例如终止进程并记录结果)。如果编码挂起并不断出现相同的错误,则不会执行命令的第二部分。如果我将行更改为:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -q error && { pkill HandBrakeCLI ; echo $ITEM >> err.log; })
因此,遇到错误时 grep 命令会退出,整个脚本会退出,而不会处理循环中的任何其他项目。但奇怪的是,如果我在编码挂起时从另一个 shell 中终止 HandBrake 进程,它就会正确地转到下一个项目。
根据 markp-fuso 的回答,我将 HandBrake 调用行改为:
脚本中还有一些额外的行需要成功完成编码,因此我将其设置为编码成功(即未满足错误条件)的条件。删除后,脚本按预期运行。