Pandoc batch conversion
overall and good stuff

This is pretty good.  I definitely wouldn't call the code dirty.  Good stuff:


The indentation is good
putting double quotes around variable substitutions is a best practice
using $() for command substitution is the best practice also
the #! is good
providing meaningful output to the user is nice
the variable names are ok


suggestions


I get putting rm -r out; mkdir out on one line sounds good because they're related, but it doesn't help the readability here.  If you want to tie them together so that the mkdir doesn't run unless rm succeeds then you could do rm -r out &amp;&amp; mkdir out.  Otherwise I'd put them on two lines.  Breaking up things with blank lines, as you've already done, is enough to make clear which things belong together.
for f in src/*.md certainly works most of the time, but will break if there's any white space in a filename.  Fixing this involves using find.  This answer is part of a duped question, but it may be a bit easier to follow.
Having f and filename as variables is a bit confusing.  For something this short it is pretty harmless which is why I said they were ok above.  If you want to tweak this f might make more sense as fullpath or fqfn.  And filename might be better as basename or base.
add if ! which pandoc... near the top to catch if pandoc is missing.


if ! which pandoc &gt; /dev/null; then
        echo you need pandoc
        exit 1
fi


further reading


shellcheck is handy.  You can run it locally or in your CI pipeline or manually paste something into their site.
bash best practices by Yaroslav Tkachenko is a nice quick read on bash best practices.
google shell style guide is even more in-depth with best practices.
env is good for portability but this is rarely an issue with bash.  It might become a more current problem if Apple dumps bash after adopting zsh as the default.