Search code examples
bashinfinite-loop

Why does shift with an argument cause an infinite loop in this bash script?


I have the following bash script:

#!/bin/bash

while (( "$#" )); do

  case $1 in
    --foo)
      foo=$2
      ;;
    --bar | -b)
      bar=$2
      ;;
    *)
      echo "what?"
      ;;
  esac

  shift
  shift

done

echo $foo
echo $bar

If I run ./my_script.sh -b first --foo second --third I get

what?
second
first

But if I change the two shift statements to a single shift 2 I just get an infinite loop of what?s. What difference between shift; shift and shift 2 causes this?


Solution

  • From the bash manual documentation of shift n:

    If n is zero or greater than $#, the positional parameters are not changed.

    So if $# is 1 and you execute shift 2, nothing happens but the return status will be non-zero, indicating failure.

    Posix requires that the argument n be no greater than $#. If you fail to ensure that, the script might be terminated (if it is not interactive) or the shift command might terminate with a non-zero status. So even aside from this particular problem, portable code should not use shift n unless it is known that there are at least n arguments.