find . -name "*.mov" -exec bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 20 -pix_fmt yuv420p "${0/.mov}.mp4"' {} \;

Above command works perfectly when I run it manually but I could not put it within a function in the .bashrc file. Receiving unexpected end of line error.

function fff { find . -name "*.mov" -exec bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 20 -pix_fmt yuv420p "${0/.mov}.mp4"' {} \; }
  • 7
    What does the function itself look like? – Nasir Riley Oct 13 '18 at 4:06
  • Without seeing the actual function definition, this is just a wild guess, but: are you missing a semicolon or line break before the } that closes the function definition? – Gordon Davisson Oct 13 '18 at 5:56
  • 1
    The in-line bash script has a code injection vulnerability. Never embed {} in shell code like that. Use bash -c '...' bash {} \; instead and then $1 in the in-line script. – Kusalananda Oct 13 '18 at 7:32
  • function fff { find . -name "*.mov" -exec bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 20 -pix_fmt yuv420p "${0/.mov}.mp4"' {} \; } – bisherbas Oct 13 '18 at 11:59

The function definition you gave in a comment:

function fff { find . -name "*.mov" -exec bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 20 -pix_fmt yuv420p "${0/.mov}.mp4"' {} \; }

is missing a semicolon or line break before the } that's supposed to end the function definition. The escaped semicolon doesn't count; that's just an argument to find that ends the -exec primary. This should work:

function fff { find . -name "*.mov" -exec bash -c 'ffmpeg -i "{}" -c:v libx264 -crf 20 -pix_fmt yuv420p "${0/.mov}.mp4"' {} \; ; }
#                                                                                                             semicolon here: ^^^

...but there are still a couple of problems. First, as @Kusalananda said in a comment, injecting filenames directly into the shell command with {} isn't safe; you should pass it as an argument and use that (as "$1" etc). You're already doing that, but as $0 -- that's really supposed to be the command/function/etc name, not a regular argument, so it's better to pass something else (like find-bash) as $0, and have the actual argument be $1.

Second (again pointed out by @Kusalananda), using ${1/.mov} to remove the old ".mov" suffix might malfunction if the filename has ".mov" somewhere else in the name; ${1%.mov} will remove it specifically from the end.

Third (and much less importantly), function is a nonstandard bashism that many people prefer to avoid; the standard syntax is funcname() definition. I'd also prefer to use line breaks rather than semicolons to separate commands. With all these fixes in place, here's what I have:

fff() {
    find . -name "*.mov" -exec bash -c 'echo ffmpeg -i "$1" -c:v libx264 -crf 20 -pix_fmt yuv420p "${1%.mov}.mp4"' find-bash {} \;
  • 2
    It would also be better to use "${1%.mov}" to be sure that it's the filename suffix we're removing and not just some .mov anywhere in the file path. Also use bash or find-bash or something similar as $0 rather than -. This string would be used in any error messages generated by the embedded script. See unix.stackexchange.com/questions/156008 – Kusalananda Oct 19 '18 at 7:26
  • @Kusalananda Good points; stand by for an edit... – Gordon Davisson Oct 20 '18 at 1:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.