title: Why does my POSIX shell script exit?
body: <p>I'm no expert on shell scripting, however I'm trying to avoid an <code>exit</code> if my script below is started with <code>-1</code> option, or without it:</p>
  
  <blockquote>
  <pre><code>./empire -1
  One-time coin collecting!
  mouse_click_coords(): Coordinates must be in pairs! Exit code = 14.
  </code></pre>
  </blockquote>
  
  <p>I fail to see where the error is (?) In other words, the script worked at 100%, until I fail to remember what I've changed; except for the <em>unexpected exit</em> at the end of processing the first loop (either passed <code>-1</code> option, or wait for it, it's the same).</p>
  
  <p>The whole script follows:</p>
  
  <hr>
  
  <pre><code>#!/bin/sh
  
  is_number()
  {
      # check if exactly one argument has been passed
      test "$#" -eq 1 || print_error_and_exit 4 "is_number(): There has not been passed exactly one argument!"
  
      # check if the argument is an integer
      test "$1" -eq "$1" 2&gt;/dev/null
  }
  
  # ------------------------------------------------------------------------------
  
  print_error_and_exit()
  {
      # check if exactly two arguments have been passed
      test "$#" -eq 2 || print_error_and_exit 2 "print_error_and_exit(): There have not been passed exactly two arguments!"
  
      # check if the first argument is a number
      is_number "$1" || print_error_and_exit 3 "print_error_and_exit(): The argument #1 is not a number!"
  
      bold=$(tput bold)
      red=$(tput setaf 1)
      nocolor=$(tput sgr0)
  
      echo "$bold$red$2 Exit code = $1.$nocolor" &gt;&amp;2
      exit "$1"
  }
  
  # ------------------------------------------------------------------------------
  
  check_for_prerequisite()
  {
      # check if exactly one argument has been passed
      test "$#" -eq 1 || print_error_and_exit 1 "check_for_prerequisite(): There has not been passed exactly one argument!"
  
      # check if the argument is a program which is installed
      command -v "$1" &gt; /dev/null 2&gt;&amp;1 || print_error_and_exit 127 "check_for_prerequisite(): I require $1 but it's not installed :-("
  }
  
  check_for_prerequisite "xdotool"
  check_for_prerequisite "wmctrl"
  check_for_prerequisite "shuf"
  check_for_prerequisite "xdpyinfo"
  check_for_prerequisite "awk"
  check_for_prerequisite "printf"
  
  # ------------------------------------------------------------------------------
  
  print_usage_and_exit()
  {
      # check if exactly one argument has been passed
      test "$#" -eq 1 || print_error_and_exit 1 "print_usage_and_exit(): There has not been passed exactly one argument!"
  
      # check if both of the arguments are numbers
      is_number "$1" || print_error_and_exit 16 "print_usage_and_exit(): The argument is not a number! Exit code expected."
  
      echo "Usage:   $0 [-1]"
      echo "         -1: One-time coin collect."
      echo "Default: Repeat coin collecting until interrupted."
      exit "$1"
  }
  
  # ------------------------------------------------------------------------------
  
  no_repeat=0
  
  while getopts ":1h" option
  do
      case "$option" in
          1)
            no_repeat=1
            ;;
          h)
            print_usage_and_exit 0
            ;;
          *)
            print_usage_and_exit 1 &gt;&amp;2
            ;;
      esac
  done
  
  # ------------------------------------------------------------------------------
  
  # global constants
  window_name_chrome="Goodgame Empire - Google Chrome"
  screen_resolution=$(xdpyinfo | awk '/dimensions:/ {print $2}')
  
  # global variables
  previous_rand=10
  operation_add=1
  
  # ------------------------------------------------------------------------------
  
  generate_random_number()
  {
      # check if exactly two arguments have been passed
      test "$#" -eq 2 || print_error_and_exit 5 "generate_random_number(): There have not been passed exactly two arguments!"
  
      # check if the arguments are both numbers
      is_number "$1" || print_error_and_exit 6 "generate_random_number(): The argument #1 is not a number!"
      is_number "$2" || print_error_and_exit 7 "generate_random_number(): The argument #2 is not a number!"
  
      # generate one pseudo-random integer within the specified range
      shuf -i "$1-$2" -n 1
  }
  
  # ------------------------------------------------------------------------------
  
  activate_window_via_name() {
      # check if exactly one argument has been passed
      test "$#" -eq 1 || print_error_and_exit 8 "activate_window_via_name(): There has not been passed exactly one argument!"
  
      xdotool search --name "$1" windowactivate --sync
  }
  
  # ------------------------------------------------------------------------------
  
  maximize_active_window() {
      # check if no argument has been passed
      test "$#" -eq 0 || print_error_and_exit 9 "maximize_active_window(): There has been passed some argument, none expected!"
  
      wmctrl -r :ACTIVE: -b add,maximized_vert,maximized_horz
  }
  
  # ------------------------------------------------------------------------------
  
  mouse_click() {
      # check if exactly two arguments have been passed
      test "$#" -eq 2 || print_error_and_exit 10 "mouse_click(): There have not been passed exactly two arguments!"
  
      # check if both of the arguments are numbers
      is_number "$1" || print_error_and_exit 11 "mouse_click(): The argument #1 is not a number!"
      is_number "$2" || print_error_and_exit 12 "mouse_click(): The argument #2 is not a number!"
  
      # 1. invert the operation_add boolean value,
      #    it seems Bash does not have inbuilt command for that
      # N: operation_add determines whether we will be adding or
      #    subtracting the random number later
  
      operation_add=$((1 - operation_add))
  
      # 2. generate pseuso-random integer between 0 and 7, inclusive,
      #    if the generated number is the same as the previous_rand,
      #    generate until it is different
      # N: rand will be later used as pixel offset from the given coordinates
  
      # we define a constant for randomness
  
      randomness=7
  
      rand=$(generate_random_number 0 "$randomness")
  
      while [ "$rand" -eq "$previous_rand" ]
      do
          rand=$(generate_random_number 0 "$randomness")
      done
  
      # 3. we don't want to repeat clicks right with the same offset,
      #    so we store information about the previous_rand here
  
      previous_rand="$rand"
  
      # 4. depending on the boolean value of operation_add,
      #    we either add the rand, or subtract it to/from the position x/y
  
      if [ "$operation_add" -eq 1 ]
      then
          pos_x=$(($1 + rand))
          pos_y=$(($2 + rand))
      else
          pos_x=$(($1 - rand))
          pos_y=$(($2 - rand))
      fi
  
      #  activate Goodgame Empire window and wait for sync,
      #  we need to do this before each click,
      #  because the user may have clicked on some other window
      #  during the 2 second delay
      activate_window_via_name "$window_name_chrome"
  
      maximize_active_window
  
      # xdotool can move mouse and simulate button clicks and more
      # ----------------------------------------------------------
          # move the mouse cursor to the given position and wait for sync
          # click the left mouse button
          # restore the original mouse cursor position and wait for sync
          # wait for 2 seconds
      xdotool \
          mousemove --sync "$pos_x" "$pos_y" \
          click 1 \
          mousemove --sync restore \
          sleep 2
  }
  
  # ------------------------------------------------------------------------------
  
  mouse_click_coords() {
      while [ "$#" -gt 1 ]
      do
          mouse_click "$1" "$2"
  
          shift 2
      done
  
      test "$#" -eq 1 || print_error_and_exit 14 "mouse_click_coords(): Coordinates must be in pairs!"
  }
  
  # ------------------------------------------------------------------------------
  
  collect_coins_1920x1080() {
      mouse_click_coords \
          1895 955 \
          1104 691 \
          1131 660 \
          1145 570 \
          1199 381
  }
  
  
  # ------------------------------------------------------------------------------
  
  collect_coins_3840x1080() {
      mouse_click_coords \
          3815 955 \
          3024 691 \
          3051 660 \
          3065 570 \
          3119 381
  }
  
  # ------------------------------------------------------------------------------
  
  collect_coins() {
      case "$screen_resolution" in
          1920x1080) collect_coins_1920x1080
          ;;
          3840x1080) collect_coins_3840x1080
          ;;
      esac
  }
  
  # ------------------------------------------------------------------------------
  
  if [ "$no_repeat" -eq 0 ]
  then
      echo "Repeating coin collecting until CTRL+C is pressed!"
  
      while true
      do
          collect_coins
  
          # wait for 10 minutes
          sleep 600
      done
  else
      echo "One-time coin collecting!"
  
      collect_coins
  fi
  </code></pre>