You have the right idea. But it won’t work if the loop executes with f == 1.mp4
, then again with f == 1.ass
, and so on.
So you want to modify the loop to only iterate over .mp4 files. Then you want to strip the .mp4
extension from the value of f
, that is, strip the last 4 characters from the value of f
, using ${f:0: -4}
(this means “get a substring of f
, starting at character 0 and ending at 5 characters before the end”).
You obviously want to terminate the loop with done
. I also suggest wrapping the parameters in quotes, to prevent word splitting (that is, if the filenames contain certain characters, they might be split into multiple arguments to ffmpeg).
Putting it all together:
for f in *.mp4; do f=${f%.*}; ffmpeg -i "$f.mp4" -vf ass="$f.ass" "$f-output.mp4"; done
Of course, once you have run this, you need to get rid of all the output files before you can run it again. Or you can just put the output files in a different directory to begin with.
Edit: Another user posted an answer, which seems to have been deleted. It was a good answer but lacked explanation. It was basically the same as my answer, except that it used ${f%.mp4}
to strip the .mp4
extension. My answer is probably slightly more complex but slightly more efficient, so it’s basically a matter of personal preference.
Edit 2: Based on the link provided by llogan’s comment, I have made these changes:
- Remove the quotes in the assignment, as assignments are not subject to word splitting (this is also stated in the bash man page).
- Use
${f%.*}
to strip the extension. This strips a dot followed by any sequence of characters from the end. It looks for the shortest possible match, so it’s really looking for a dot followed by any sequence of non-dot characters at the end.