15

Мне нужно конвертировать видео, но я не знаю, где они, поэтому мне нужно их find . Как я могу дать результат и имя выходного файла для FFmpeg с xargs?

Я уже выяснил, что с помощью этой команды я могу построить два параметра:

find . -iname "*.mov" -printf "%p %f\n"

Я не могу найти ничего связанного с руководством xargs . Я хочу что-то вроде этого:

find . -iname "*.mov" -printf "%p %f\n" | xargs ffmpeg -i {param1} -f flv {param2}

Как я могу это сделать?

8 ответов8

9

Причина, по которой люди используют xargs в сочетании с find, заключается в том, что несколько имен файлов будут переданы в один и тот же вызов программы независимо от того, какая программа запускает xargs . Например, если find возвращает файлы foo, bar и baz, следующее запустит mv только один раз:

find sourceDir [...] -print0 | xargs -0 mv -t destDir

По сути, он вызывает mv следующим образом:

mv -t destDir foo bar baz

Если вам не нужно или не нужно это поведение (как я полагаю, здесь имеет место), вы можете просто использовать find 's -exec .


В этом случае простым решением было бы написать короткий сценарий оболочки, например:

#!/usr/bin/env bash
[[ -f "$1" ]] || { echo "$1 not found" ; exit 1 ; }
P="$1"
F="$( basename $P )"
ffmpeg -i "$P" -f flv "$F"

Сохраните как myffmpeg.sh и запустите chmod +x myffmpeg.sh . Затем выполните следующее:

find . -iname "*.mov" -exec /path/to/myffmpeg.sh {} \;

Это вызовет скрипт оболочки один раз для каждого найденного файла. Сценарий оболочки, в свою очередь, извлекает имя файла из полного пути и вызывает ffmpeg с соответствующими аргументами.

3

Вы должны сделать это, как и все ответы, но ТОЧНОЕ использование xargs будет примерно таким:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs

Так что в вашем случае это будет:

find . -iname "*.mov" -printf "%p %f\n" | xargs -l bash -c 'echo ffmpeg -i $0 -f flv $1' | xargs

PS: Это ответ на вопрос о xargs для тех, кто ищет ответ именно для нескольких параметров xargs в одной команде xargs .

3

Я не получил решение, которое ожидалось, поэтому я нашел свое. @ Даниэль ответит хорошо, но для этого нужен сценарий оболочки. Один лайнер быстрее, и мне это нравится больше :), также более простое решение, чем написание скрипта.

Я мог бы использовать один аргумент и обработать его с помощью basename и используя sh -c

find . -iname "*.mov" -print0 | xargs -0 -i sh -c 'ffmpeg -i {} -f flv `basename {}`'

-I указывает xargs заменить {} на текущий аргумент.
Вывод команды внутри `` распечатан на стандартный вывод (функция bash), поэтому basename {} будет оценено как пустое имя файла и распечатано.
-0 для правильной обработки специальных имен файлов, но вам нужно передать параметры с опцией -print0 с помощью find

2

Что-то вроде этого поможет, сохранит полный путь, обработает пространство, переименует folder/movie.mov в folder/movie.flv и т.д.

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "${movie%.mov}.flv"
done

И если я вас неправильно понял, и вы хотите все фильмы .flv в текущем каталоге, используйте вместо этого:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
done
1

Я не уверен, можете ли вы или как это сделать с помощью xargs.

Но что-то вроде этого должно работать для вас:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
1

Почему бы просто не переместить параметры ffmpeg, чтобы они соответствовали формату результатов команды find ?

find . -iname "*.mov" -printf "%p %f\n" | xargs -r -n2 ffmpeg -f flv -i

Обратите внимание на добавление опции -r к xargs, чтобы предотвратить запуск ffmpeg, если не найдены файлы .mov .

Я добавил опцию -n2 в xargs, чтобы ограничить количество элементов процессов xargs до двух одновременно. В этом случае элементами являются путь к файлу и имя файла. Если не задана опция -n , xargs будет обрабатывать как можно больше входных элементов за одно выполнение.

0

Альтернатива ответу Zoredache с использованием привязки имени (и с использованием разных разделителей, чтобы избежать проблемы пробелов в именах файлов):

IFS="\t" find -iname "*.mov" -printf "%p\t%f\n" | while read path file; do
    ffmpeg -i $path -f flv $file
done

Конечно, вы также можете использовать разделители с аргументом find -a array который использовал другой ответ, но иногда именованные аргументы более понятны.

0

Вы можете запустить ffmpeg непосредственно из команды find следующим образом:

find . -iname "*.mov" -exec ffmpeg -i "%p" -f flv "%f" \;

Обратите внимание на кавычки вокруг параметров ffmpeg, если в имени файла есть пробелы, а экранированная точка с запятой отмечает конец выполненной команды.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .