Bash function with `getopts` only works the first time it's run

bash getopts use an environment variable OPTIND to keep track the last option argument processed. The fact that OPTIND was not automatically reset each time you called getopts in the same shell session, only when the shell was invoked. So from second time you called getopts with the same arguments in the same session, OPTIND wasn't changed, getopts thought it had done the job and do nothing.

You can reset OPTIND manually to make it work:

$ f -a 123
-a was triggered, Parameter: 123

or just put the function into a script and call the script multiple times.

zsh getopts is slightly different. OPTIND was normally reset to 1 each time upon exit from shell function.

It is a god habit to declare local variables in any function. If you declare $opt, $OPTARG and $OPTIND then getopts will work any times you call the function. Local variables are discarded after the function finished.

function some_func {
  declare opt
  declare OPTARG
  declare OPTIND

  while getopts ":a:" opt; do
    echo $opt is $OPTARG

You need to set OPTIND=1 at the start of function f. By default it is 1, but then gets incremented as your args are parsed. When you call getopts again it carries on where it left off. You can see this if your 2nd call is:

f -a 123 -a 999

when it will print the 999.