Условное выполнение команд на основе вывода grep в скрипте оболочки

Вопрос или проблема

Я использую скрипт для транскодирования большого количества фильмов с помощью командной строки 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 стандартный поток ошибок (stderr)?

Я могу успешно 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 на экран. Мне не ясно, как я могу использовать это для выполнения конкретных команд, например, убить 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 "ошибка найдена" ; echo $ITEM >> failed.txt

Но скрипт просто завершается при обнаружении ошибки, не переходя к следующему элементу в цикле.

Любая помощь приветствуется!

обновлено для ответа на вопрос тердона:

Мне также было любопытно о первоначальном echo “” | в вызове HandBrake. Это было в оригинальном скрипте, упомянутом в начале запроса, но мне не ясно, зачем это нужно. Я запускаю это на MacOS. Полный скрипт:

#!/bin/bash

SOURCE=$1
ENCODER=$2
OPTS=$3

TOTAL=$(find "$SOURCE" \! -name ".*" -type f | wc -l)
CURR=0
DESTINATION="PROCESSED"

ENCODER=${ENCODER:="hw"}

# Создать директории
[[ -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"

  # Получить правильный пресет
  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 "Обработка" $FILE "с использованием пресета" $PRESET
  echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 2> /dev/null

  CURR=$((CURR + 1))
  echo "готово" $CURR "из"$TOTAL

done< <(find "$SOURCE" \( -iname '*.mp4' -or -iname '*.mov'  -or -iname '*.MP4' -or -iname '*.MOV' \) -print0)

Ответ или решение

Условное выполнение команд на основе вывода grep в shell-скрипте

Как IT-эксперт, я понимаю вашу задачу и необходимость в создании скрипта для обработки фильмов с использованием HandBrakeCLI. Учитывая ваш запрос, давайте рассмотрим, как можно организовать условное выполнение команд в зависимости от вывода grep, чтобы ваша прога могла корректно обрабатывать ошибки, возникающие при кодировании.

Цели

  1. Мониторинг стандартного вывода (stdout): Отображение информации на экране.
  2. Мониторинг ошибок (stderr): Поиск специфической ошибки.
  3. Условное выполнение после ошибки: Завершение процесса, ведение логов и переход к следующему файлу.

Решение

Чтобы реализовать поставленные задачи, нам нужно использовать grep для мониторинга выхода стандартного потока ошибок и организовать условную логику для обработки ошибок. Вот как вы можете сделать это в вашем скрипте:

#!/bin/bash

SOURCE=$1
ENCODER=$2
OPTS=$3

TOTAL=$(find "$SOURCE" \! -name ".*" -type f | wc -l)
CURR=0
DESTINATION="PROCESSED"

ENCODER=${ENCODER:="hw"}

# Создание директории
[[ -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"

  # Определение пресета
  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 "Обработка" $FILE "с использованием пресета" $PRESET

  # Запуск HandBrakeCLI и мониторинг stderr
  {
    echo "" | HandBrakeCLI -i "$ITEM" -o "$OUTPUT" --preset="$PRESET" $OPTS 2>&1 | grep -i "error" > /dev/null
  } || {
    echo "Ошибка при обработке $ITEM" >> err.log
    echo "Текущий файл был пропущен из-за ошибки."
    continue
  }

  CURR=$((CURR + 1))
  echo "Завершено" $CURR "из" $TOTAL

done < <(find "$SOURCE" \( -iname '*.mp4' -or -iname '*.mov' -or -iname '*.MP4' -or -iname '*.MOV' \) -print0)

Объяснение решения

  1. Обработка вывода: Мы перенаправляем stderr в stdout (2>&1) и затем используем grep для фильтрации ошибок. Обратите внимание на > /dev/null, который скрывает вывод grep.

  2. Условное выполнение: Использование конструкции || позволяет выполнить команду в случае возникновения ошибки. Если команда завершилась неуспешно (мы нашли "error"), скрипт производит логирование, продолжает выполнение и переходит к следующему входному файлу.

  3. Логирование: В случае возникновения ошибки мы записываем информацию в лог-файл err.log и выводим сообщение, чтобы проинформировать пользователя об этом.

Остальные аспекты

  • Echo "" | в вызове HandBrakeCLI в вашем исходном скрипте может быть необходимо, если HandBrakeCLI ожидает ввод, связанный с интерфейсом. Если HandBrakeCLI может работать без этого, вы можете убрать этот фрагмент.

  • Проверка условий: Убедитесь, что ffprobe корректно определяет разрешение видео; это поможет в правильном назначении пресетов.

Данный алгоритм обеспечит вам необходимую функциональность для стабильного выполнения вашей задачи. Если у вас возникнут дополнительные вопросы или потребуется помощь, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...