Почему этот однослойный клоббер загружается?

Я написал это, чтобы помочь мне закодировать несколько видео:

find -name '*.mkv' -exec HandBrakeCLI -Z "Android Tablet" \ -c "1-3" -m -O --x264-tune film -E copy --decomb -s 1 -i {} \ -o `echo {} | tr mkv m4v` \; 

Однако это не так катастрофично – он берет каждый файл 700-900 МБ и заменяет его файлом 36 КБ.

Примечательно, что HandBrake способен читать и распечатывать свойства видеофайла; это происходит только тогда, когда он переходит к кодировке, что он терпит неудачу, потому что файл недействителен. Таким образом, кажется, что переписывание происходит, когда оно доходит до …

 -o `echo {} | tr mkv m4v` 

… но я не уверен, зачем это нужно. Я просто пытаюсь изменить имя выходного файла из whatever.mkv на any.m4v

Имена файлов не имеют пробелов. Например, они имеют форму 12-the-revenge.mkv .

Выраженное выражение: echo {} | tr mkv m4v echo {} | tr mkv m4v (что не то, что вы хотите, по разным причинам, см. ниже) расширяется один раз, когда команда find анализируется. Если вы используете bash , он обычно расширяется до {} :

 $ echo {} | tr mkv m4v {} 

И действительно, это происходит на каждой оболочке, установленной на моей машине, кроме рыбы, которая выводит пустую строку. Предполагая, что вы не используете fish , тогда find аргументы на самом деле будет:

 find -name '*.mkv' -exec HandBrakeCLI -Z "Android Tablet" \ -c "1-3" -m -O --x264-tune film -E copy --decomb -s 1 -i {} \ -o {} \; 

Короче говоря, HandBrakeCLI получает тот же файл для ввода и вывода, и я думаю, что это то, что вы видите, хотя ваше описание симптомов не очень точное.

К сожалению, нет простого способа найти нужную вам замену расширения, которую вы хотите сделать в рамках действия -exec . Вы можете сделать это, передав команду bash -c , но это потребует дополнительных, запутывающих цитат в командной строке. Более чистым и понятным решением является создание файла сценария оболочки, который может выполнять итерацию по его аргументам:

Файл: mkvtom4v.sh (убедитесь, что вы chmod a+x mkvtom4v.sh )

 #!/bin/bash for file in "$@"; do HandBrakeCLI -Z "Android Tablet" -c "1-3" -m -O \ --x264-tune film -E copy --decomb -s 1 \ -i "$file" -o "${file/%.mkv/.m4v}" done 

А затем вызовите его с помощью find:

 find /path/to/directory -name '*.mkv' -exec /path/to/mkvtom4v.sh {} + 

Некоторые примечания:

  1. Не используйте обратные сигналы ( some command ); они устарели много лет. Используйте $(some command) , которая более читаема и позволяет вложенность.

  2. tr определенно не то, что вы хотите. Это характер по переводу персонажей. Например, tr aeiou AEIOU сделает все vOwEls UppErcAsE. tr mkv m4v изменит каждый k на 4 . Подробнее см. man tr (или info tr ).

  3. "${file/%.mkv/.m4v}" – это идиосинкразированный синтаксис поиска и замены bash. В этом случае это означает: «Возьмите значение $file , и если оно заканчивается на .mkv (значение % означает« заканчивается »в этом контексте), замените его на .m4v ». Существует множество других базизмов для редактирования значения переменной. man bash и найдите «Расширение параметров».

  4. С помощью GNU find вы можете использовать {} + в конце команды -exec (вместо \; ). Он будет заменен как можно большим количеством найденных имен файлов. См. info find для получения более подробной информации.