Estou usando um script para transcodificar um monte de filmes usando a versão de linha de comando do HandBrake. Estou usando uma versão modificada do script aqui:
https://gist.github.com/ralphcrisostomo/56fc395b1646bd55aeeb2eb442043887
O problema que tenho é que a transcodificação trava de forma não reproduzível em um pequeno subconjunto de filmes. Isso é acompanhado por um erro muito específico no stderr.
O que eu gostaria de fazer é 1) seguir o stdout (mas não o stderr) na tela, 2) monitorar o stderr para a condição de erro e 3) se a condição de erro for satisfeita, encerrar o processo do HandBrake, registrar o arquivo problemático e passar para o próximo.
Atualmente, o comando de transcodificação se parece com isto:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 2> /dev/null
que satisfaz 1).
Seguindo os conselhos aqui:
Como executar grep no fluxo de erro padrão (stderr)?
Posso executar grep com sucesso no fluxo de erros para a palavra relevante, por exemplo
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -i error)
ou
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 3>&2 2>&1 1>&3- | grep -i "error"
No entanto, tudo isso fará com que ele imprima a linha relevante do stderr na tela. Não está claro para mim como posso usar isso para executar comandos específicos, por exemplo, kill HandBrakeCLI ; echo $ITEM >> err.log
Tentei usar grep -q para testar se a correspondência foi bem-sucedida assim:
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
Mas o script simplesmente sai ao encontrar o erro, sem passar para o próximo item do loop.
Qualquer ajuda será bem-vinda!
atualizado para responder à pergunta de Terdon:
Também fiquei curioso sobre o echo inicial "" | na invocação do HandBrake. Estava no script original referenciado no topo da consulta, mas também não está claro para mim por que é necessário. Estou executando isso no MacOS. O script completo é
#!/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)
Atualização 061224
Seguindo a sugestão de markp-fuso, modifiquei a linha que chama o HandBrake da seguinte forma:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -i error && { pkill HandBrakeCLI ; echo $ITEM >> err.log; })
Isso imprime o erro relevante no stdout quando encontrado, mas só executa a segunda parte (por exemplo, matando o processo e registrando o resultado) quando a codificação atual é concluída. Se a codificação simplesmente travar e continuar gerando o mesmo erro, a segunda parte do comando não será executada. Se eu alterar a linha para:
echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" 2> >(grep -q error && { pkill HandBrakeCLI ; echo $ITEM >> err.log; })
Então o comando grep sai ao encontrar o erro, o script inteiro sai sem processar mais nenhum item no loop. Estranhamente, porém, se eu matar o processo HandBrake de outro shell quando o encode trava, ele então moverá corretamente para o próximo item.