Сценарий оболочки во время цикла чтения выполняется только один раз - PullRequest
8 голосов
/ 05 апреля 2011

Я пишу сценарий оболочки для пакетной обработки файлов .mov с моей камеры через Ручной тормоз для экономии места на жестком диске. Сценарий выполняет поиск в каталоге с помощью команды «find», а затем запускает Handbrake для каждого найденного файла .mov, сопоставляя дату создания полученного файла с датой исходного файла с помощью «touch».

Я изначально делал это с для цикла:

for i in $(find "$*" -iname '*.mov') ; do
  ~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
  touch -r "$i" "$i".mp4
done

Это сработало, но не удалось, если во входных файлах были пробелы в именах файлов. Поэтому я попробовал цикл while вместо:

find "$*" -iname '*.mov' | while read i ; do
  ~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
  touch -r "$i" "$i".mp4
done

Проблема с этим циклом заключается в том, что он работает для первого файла в каталоге, а затем выходит из цикла. Обратите внимание, что если я подставлю «echo $ i» в теле цикла while, он напечатает все файлы .mov в каталоге, поэтому цикл структурирован правильно.

Я полагаю, что есть частичный ответ на мой вопрос по этой теме потока потоков . Но решение специфично для ssh и не решает общую проблему. Кажется, что-то связано с тем, что stdin используется подпроцессом, но я не совсем понимаю, как это работает.

Любой совет?

Я на OSX 10.6

Ответы [ 6 ]

2 голосов
/ 02 июля 2013

Взято из этого ответа : теперь я ничего не отображаю в HandbrakeCLI, чтобы убедиться, что он не использует тот же stdin, что и мой скрипт:

find . -name "*.mkv" | while read FILE
do
    echo "" | handbrake-touch "$FILE"

    if [ $? != 0 ]
    then
        echo "$FILE had problems" >> errors.log  
    fi
done

... и работает как задумано /ожидается.

2 голосов
/ 06 апреля 2011

Одной из возможностей является использование безопасной находки :

while IFS= read -r -d '' -u 9
do
    ~/Unix/HandbrakeCLI --input "$REPLY" --output "$REPLY".mp4 --preset="Normal"
    touch -r "$REPLY" "$REPLY".mp4
done 9< <( find "$@" -type f -print0 )

Это должно быть POSIX-совместимым, но работает, только если ни HandbrakeCLI, ни touch не читаются из стандартного ввода и , никакие имена файлов не содержат символов новой строки:

find "$@" -type f -print0 | while IFS= read -r
do
    ~/Unix/HandbrakeCLI --input "$REPLY" --output "$REPLY".mp4 --preset="Normal"
    touch -r "$REPLY" "$REPLY".mp4
done
1 голос
/ 05 апреля 2011

Вы, вероятно, работаете с шеллоптом '-e' (выход при ошибках)

Попробуйте

set +e
0 голосов
/ 09 января 2013

Подумайте только об использовании find для вызова оболочки вместо того, чтобы обернуть find в цикл while.

find "$@" -iname '*.mov' -exec sh -c '
    ~/Unix/HandbrakeCLI --input "$1" --output "$1".mp4 --preset="Normal"
    touch -r "$1" "$1".mp4
' _ {} ';'
0 голосов
/ 08 октября 2012

У меня такая же проблема. Я думаю, что HandbrakeCLI потребляет стандартный ввод. У меня нет моей действительной системы здесь, но мои тесты показывают, что это, вероятно, происходит.

"output" - это файл с номерами 1-10, каждый в своей строке.

while read line ; do echo "MAIN: $line"; ./consumer.sh; done < output

consumer.sh:

#!/bin/sh

while read line ; do
  echo "CONSUMER: $line"
done

Результаты:

MAIN: 1
CONSUMER: 2
CONSUMER: 3
CONSUMER: 4
CONSUMER: 5
CONSUMER: 6
CONSUMER: 7
CONSUMER: 8
CONSUMER: 9
CONSUMER: 10

Изменение внешнего цикла while решит проблему:

while read line ; do echo "MAIN: $line"; ./consumer.sh < /dev/null; done < output

Результаты:

MAIN: 1
MAIN: 2
MAIN: 3
MAIN: 4
MAIN: 5
MAIN: 6
MAIN: 7
MAIN: 8
MAIN: 9
MAIN: 10
0 голосов
/ 18 августа 2011

Эта ссылка устранила проблему для меня в Ubuntu Linux 11.04.

Предотвращение выхода дочернего процесса (HandbrakeCLI) из родительского сценария на выход

Воткод, который работает для меня:

ls -t *.mpeg | tail -n +2 | while read name
do echo "$name" ; in="$name" ; out=coded/"`echo $name | sed 's/.mpeg$/.mkv/'`"
echo "" | HandBrakeCLI -i "$in" -o "$out" -a '1,2' ; mv -v "$name" trash/"$name"
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...