0

I am not sure if switch is the proper terminology as I am new to Unix.

I have a shell script that requires what I call a switch to function properly but I also want to pass arguments:

./scriptname -cm

where if I run just ./scriptname it would fail. But I also want to pass various arguments:

./scriptname -cm arg1 arg2 arg3 arg4

This appears to fail due to the -cm. Normally when I do ./scriptname arg1 arg2 arg3 it will work properly but once I add the switch it fails. Suggestions?

Edit1:

Adding some more relevant code:

./scriptname -cm

will call

scriptname

gencmlicense()
{
echo $2
do stuff
}

gentermlicense()
{
do stuff
}

if [ "$1" = "-cm" ] ; then
    gencmlicense
elif [ "$1" = "-term" ] ; then
    gentermlicense
fi

If I added an argument the echo $2 would not print out the second argument passed.

Jens
  • 69,818
  • 15
  • 125
  • 179
Jay
  • 73
  • 1
  • 2
  • 10
  • note: when passing arg1 arg2 etc the shell appears to think they are commands not arguments – Jay Jun 22 '18 at 17:34
  • 1
    I'm unable to reproduce this problem. Can you include some code? – that other guy Jun 22 '18 at 17:47
  • 1
    There is absolutely no problem passing options and arguments like you want to do. The issue will come with how your script is handling options and arguments. So please show us. – glenn jackman Jun 22 '18 at 17:50
  • I went ahead and added some snippets of the code – Jay Jun 22 '18 at 18:12
  • Parameters are not global. Each function has their own parameter variables. `$2` in the context of `gencmlicense` is not the same `$2` in the context of the `main` script. You are calling the functions without passing any parameters therefore they don't have any `$n` parameters. – alvits Jun 22 '18 at 18:45
  • 2
    You may find [shellcheck](http://shellcheck.net) useful. In this case it says `Use gencmlicense "$@" if function's $1 should mean script's $1.` – that other guy Jun 22 '18 at 19:39
  • You need to provide a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). People are guessing at your code. Also see [How to use Shellcheck](https://github.com/koalaman/shellcheck), [How to debug a bash script?](https://unix.stackexchange.com/q/155551/56041) (U&L.SE), [How to debug a bash script?](https://stackoverflow.com/q/951336/608639) (SO), [How to debug bash script?](https://askubuntu.com/q/21136) (AskU), [Debugging Bash scripts](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html), etc. – jww Jun 23 '18 at 04:51

1 Answers1

5

If you want to pass arguments from the main script to a function unmodified, use

...
if [ "$1" = "-cm" ] ; then
    gencmlicense "$@"
elif [ "$1" = "-term" ] ; then
    gentermlicense "$@"
fi

The "$@" (with double quotes!) expands to all positional parameters. For more on this, see your shell manual, likely under "Parameter Expansion".

If your functions don't need the first positional parameter, you can shift it away:

if [ "$1" = "-cm" ]; then
    shift
    gencmlicense "$@"
elif [ "$1" = "-term" ]; then
    shift
    gentermlicense "$@"
fi

The professional way of handling options, though, is with the getopts builtin, because it is flexible and extensible, yet compact. This is what I use:

#!/bin/sh
MYNAME=${0##*/}  # Short program name for diagnostic messages.
VERSION='1.0'
PATH="$(/usr/bin/getconf PATH):/usr/local/bin"

usage () {
  cat << EOF

usage: $MYNAME [-hvVx] [-a arg] ...

  Perform nifty operations on objects specified by arguments.

Options:
  -a arg   do something with arg
  -h       display this help text and exit
  -v       verbose mode
  -V       display version and exit
  -x       debug mode with set -x

EOF
  exit $1
}

parse_options () {
  opt_verbose=false
  while getopts :a:hvVx option; do
    case $option in
      (a)  opt_a=$OPTARG;;
      (h)  usage 0;;
      (v)  opt_verbose=true;;
      (V)  echo "version $VERSION"; exit 0;;
      (x)  set -x;;
      (?)  usage 1;;
    esac
  done
}

#-------------------------------------------------------------#
#                     Main script                             #
#-------------------------------------------------------------#

parse_options "$@"
shift $((OPTIND - 1))   # Shift away options and option args.
    ...rest of script here...
Jens
  • 69,818
  • 15
  • 125
  • 179
  • this seems to work very well. thank you. what if I need to make sure the script only runs if there are arguments? not just `-cm` – Jay Jun 22 '18 at 20:16
  • `if [ "$1" = "-cm" ] ; then` `if [ "$#" -gt 1 ]; then` `shift` `gencmlicense "$@"` – Jay Jun 22 '18 at 20:17
  • @Jay I've inserted `shift $((OPTIND - 1))` to shift away the options. After that you can test for remaining arguments (such as a list of files) with `if test $# -eq 0; then echo Missing arguments; fi` – Jens Jun 22 '18 at 21:02