Как я могу использовать два параметра одновременно с xargs?

18

Мне нужно конвертировать видео, но я не знаю, где они, поэтому они мне нужны 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}

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

kissgyorgy
источник
Те из вас наткнуться на этот вопрос , потому что вы ищете ответ на вопрос о многочисленных спорах с xargs вообще возможно , захотите проверить stackoverflow.com/questions/3770432/... .
Крис Олдвуд

Ответы:

4

Нечто подобное будет делать трюк и сохранить полный путь, ручки пространство, переименование 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
Маттиас Анберг
источник
3
Если вы хотите, чтобы это был простой способ, просто поместите все в одну строку. ;)
Маттиас Анберг
9

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

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

По сути, это вызывает mvследующее:

mv -t destDir foo bar baz

Если вам не нужно или не нужно такое поведение (как я полагаю, здесь имеет место), вы можете просто использовать finds -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с соответствующими аргументами.

Даниэль Бек
источник
4

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

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

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

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

kissgyorgy
источник
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команде.

Sauliux Zyziux
источник
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 обработает как можно больше входных элементов за одно выполнение.

ZaSter
источник
Это не будет работать, если найдено более одного файла AFAICT.
Даниэль Бек
Это работает только один раз для меня, но я не понимаю, почему это останавливается после первого. Любая идея ?
Kissgyorgy
на самом деле это не работает
kissgyorgy
Дэниел-Бек и @Walkman были правы насчет одиночной казни. Чтобы решить эту проблему, я отредактировал этот ответ, чтобы ограничить число элементов, которые xargs обрабатывает одновременно, с помощью опции -n2 . Без - N2 , xargs выполняется только один раз , если он может обрабатывать число входных элементов , которые он получает через трубу. Также следует отметить, что это решение работает только тогда, когда имена файлов и пути к файлам не содержат пробелов.
Застер
1

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

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

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
Zoredache
источник
1
Это не правильно обрабатывает пробелы в именах файлов / путях, не так ли?
Даниэль Бек
1

Альтернатива ответу 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аргументом, использованным в другом ответе, но иногда именованные аргументы более понятны.

wolf1oo
источник
0

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

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

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

Рэнди Оррисон
источник
Есть ли у вас документация по поведению -exec, которая также интерпретирует заполнители форматирования printf?
Даниэль Бек
Нет. Мозг пердеть: я думал, что% p и% f были находки, а не printf вещи. Я проголосовал за ваш ответ.
Рэнди Оррисон