I need to convert videos, but I don't know where are they, so I need to find them. How can I give the result and an output file name to FFmpeg with xargs?

I already found out that I can construct the two parameters with this command:

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

I can't find anything related in the xargs manual. I want something like this:

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

How can I do this?


8 Answers 8


Something like this will do the trick and preserve full path, handle space, rename folder/movie.mov to folder/movie.flv, etc.

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

And if I misunderstood you and you want all the .flv movies in the current directory, use this one instead:

find . -name "*.mov" | while read movie;do
  ffmpeg -i "$movie" -f flv "$(basename "${movie%.mov}.flv")"
  • 4
    If you want it as a oneliner, just put everything on one line. ;) Jan 8, 2012 at 2:58

The reason people use xargs in combination with find is that multiple file names will be passed to the same program invocation of whatever program xargs launches. For example, if find returns the files foo, bar, and baz, the following will run mv only once:

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

Effectively, it calls mv like the following:

mv -t destDir foo bar baz

If you don't need or want this behavior (as I assume is the case here), you can simply use find's -exec.

In this case, an easy solution would be to write a short shell script, like the following:

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

Save as myffmpeg.sh and run chmod +x myffmpeg.sh. Then, run the following:

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

This will invoke the shell script once for every file found. The shell script in turn extracts the file name from the full path, and calls ffmpeg with the appropriate arguments.


I did not get the solution I was expected, so I found out my own. @Daniel's answer is good, but it need a shell script. A one liner is quicker, and I like it better :) also simpler solution than writing a script.

I could use one argument and process it with basename and using sh -c

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

The -i tells to xargs to replace {} with the current argument.
Command output inside `` printed out to standard output (bash feature) so basename {} will be evaluated as the bare file name and printed out.
-0 for handling special file names properly, but you need to pass parameters with the -print0 option with find


You have to do it like all the answers up there, but the EXACT use of xargs will be something like this:

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

So in your case it will be:

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

PS: This answers the question about xargs for those who is looking for an answer exactly for multiple xargs parameters in one xargs command.


Why not simply move the options of the ffmpeg to fit the format of the results from the find command?

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

Notice the addition of the -r option to xargs to prevent it from running ffmpeg if no .mov files are found.

I have added the -n2 option to xargs to limit the number of items xargs processes to two at a time. In this case, the items are the file path and the file name. If no -n option is set, xargs will process as many input items as possible in a single execution.

  • This won't work once more than one file is found AFAICT.
    – Daniel Beck
    Jan 7, 2012 at 17:59
  • This works only once for me too, but I dont understand why it stops after the first. Any idea ?
    – kissgyorgy
    Jan 7, 2012 at 21:04
  • actually it doesnt work
    – kissgyorgy
    Jan 7, 2012 at 21:25
  • Daniel-Beck and @Walkman were correct about the single execution. To solve that problem, I have edited this answer to limit the number of items xargs processes at a time via the -n2 option. Without the -n2, xargs executes only once if it can handle the number of input items it receives through the pipe. It also should be pointed out that this solution only works when file names and file paths do not include whitespace.
    – ZaSter
    Jan 8, 2012 at 2:16

I am not sure if you can or how to do that with xargs.

But something like this should work for you:

find . -iname "*.mov" -printf "%p %f\n" | while read -a HR ; do echo ffmpeg -i ${HR[0]} -f flv ${HR[1]} ;done
  • 1
    This doesn't properly handle spaces in file names/paths, does it?
    – Daniel Beck
    Jan 7, 2012 at 17:05

An alternative to Zoredache's answer using name binding (and using different separators to avoid the issue of spaces in file names):

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

Of course you can also use the separators with the find -a array argument that the other answer had used, but sometimes named arguments are more comprehensible.


You can run ffmpeg directly from the find command like this:

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

Note the quotes around the parameters to ffmpeg, in case there are spaces in the filename, and the escaped semi-colon marks the end of the executed command.

  • Do you have documentation for the behaviour of -exec that also interprets printf formatting placeholders?
    – Daniel Beck
    Jan 7, 2012 at 13:23
  • Nope. Brain fart: I was thinking the %p and %f were find-things, not printf-things. I've voted for your answer. Jan 7, 2012 at 17:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .