Check number of arguments passed to a Bash script

BashParameter PassingCommand Line-Arguments

Bash Problem Overview


I would like my Bash script to print an error message if the required argument count is not met.

I tried the following code:

#!/bin/bash
echo Script name: $0
echo $# arguments 
if [$# -ne 1]; 
	then echo "illegal number of parameters"
fi

For some unknown reason I've got the following error:

test: line 4: [2: command not found

What am I doing wrong?

Bash Solutions


Solution 1 - Bash

Just like any other simple command, [ ... ] or test requires spaces between its arguments.

if [ "$#" -ne 1 ]; then
	echo "Illegal number of parameters"
fi

Or

if test "$#" -ne 1; then
	echo "Illegal number of parameters"
fi
Suggestions

When in Bash, prefer using [[ ]] instead as it doesn't do word splitting and pathname expansion to its variables that quoting may not be necessary unless it's part of an expression.

[[ $# -ne 1 ]]

It also has some other features like unquoted condition grouping, pattern matching (extended pattern matching with extglob) and regex matching.

The following example checks if arguments are valid. It allows a single argument or two.

[[ ($# -eq 1 || ($# -eq 2 && $2 == <glob pattern>)) && $1 =~ <regex pattern> ]]

For pure arithmetic expressions, using (( )) to some may still be better, but they are still possible in [[ ]] with its arithmetic operators like -eq, -ne, -lt, -le, -gt, or -ge by placing the expression as a single string argument:

A=1
[[ 'A + 1' -eq 2 ]] && echo true  ## Prints true.

That should be helpful if you would need to combine it with other features of [[ ]] as well.

Take note that [[ ]] and (( )) are keywords which have same level of parsing as if, case, while, and for.

Also as Dave suggested, error messages are better sent to stderr so they don't get included when stdout is redirected:

echo "Illegal number of parameters" >&2
Exiting the script

It's also logical to make the script exit when invalid parameters are passed to it. This has already been suggested in the comments by ekangas but someone edited this answer to have it with -1 as the returned value, so I might as well do it right.

-1 though accepted by Bash as an argument to exit is not explicitly documented and is not right to be used as a common suggestion. 64 is also the most formal value since it's defined in sysexits.h with #define EX_USAGE 64 /* command line usage error */. Most tools like ls also return 2 on invalid arguments. I also used to return 2 in my scripts but lately I no longer really cared, and simply used 1 in all errors. But let's just place 2 here since it's most common and probably not OS-specific.

if [[ $# -ne 1 ]]; then
	echo "Illegal number of parameters" >&2
	exit 2
fi
References

Solution 2 - Bash

It might be a good idea to use arithmetic expressions if you're dealing with numbers.

if (( $# != 1 )); then
    >&2 echo "Illegal number of parameters"
fi

>&2 is used to write the error message to stderr.

Solution 3 - Bash

On []: !=, =, == ... are string comparison operators and -eq, -gt ... are arithmetic binary ones.

I would use:

if [ "$#" != "1" ]; then

Or:

if [ $# -eq 1 ]; then

Solution 4 - Bash

If you're only interested in bailing if a particular argument is missing, Parameter Substitution is great:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT

Solution 5 - Bash

A simple one liner that works can be done using:

[ "$#" -ne 1 ] && ( usage && exit 1 ) || main

This breaks down to:

  1. test the bash variable for size of parameters $# not equals 1 (our number of sub commands)
  2. if true then call usage() function and exit with status 1
  3. else call main() function

Things to note:

  • usage() can just be simple echo "$0: params"
  • main can be one long script

Solution 6 - Bash

Check out this bash cheatsheet, it can help alot.

To check the length of arguments passed in, you use "$#"

To use the array of arguments passed in, you use "$@"

An example of checking the length, and iterating would be:

myFunc() {
  if [[ "$#" -gt 0 ]]; then
    for arg in "$@"; do
      echo $arg
    done
  fi
}

myFunc "$@"

This articled helped me, but was missing a few things for me and my situation. Hopefully this helps someone.

Solution 7 - Bash

Here a simple one liners to check if only one parameter is given otherwise exit the script:

[ "$#" -ne 1 ] && echo "USAGE $0 <PARAMETER>" && exit

Solution 8 - Bash

There is a lot of good information here, but I wanted to add a simple snippet that I find useful.

How does it differ from some above?

  • Prints usage to stderr, which is more proper than printing to stdout
  • Return with exit code mentioned in this other answer
  • Does not make it into a one liner...
_usage(){
    _echoerr "Usage: $0 <args>"
}

_echoerr(){
	echo "$*" >&2
}

if [ "$#" -eq 0 ]; then # NOTE: May need to customize this conditional
    _usage
    exit 2
fi
main "$@"

Solution 9 - Bash

In case you want to be on the safe side, I recommend to use getopts.

Here is a small example:

    while getopts "x:c" opt; do
      case $opt in
        c)
          echo "-$opt was triggered, deploy to ci account" >&2
    	  DEPLOY_CI_ACCT="true"
          ;;
            x)
              echo "-$opt was triggered, Parameter: $OPTARG" >&2 
              CMD_TO_EXEC=${OPTARG}
              ;;
            \?)
              echo "Invalid option: -$OPTARG" >&2 
        	  Usage
              exit 1
              ;;
            :)
              echo "Option -$OPTARG requires an argument." >&2 
        	  Usage
              exit 1
              ;;
          esac
        done

see more details here for example http://wiki.bash-hackers.org/howto/getopts_tutorial

Solution 10 - Bash

You should add spaces between test condition:

if [ $# -ne 1 ]; 
    then echo "illegal number of parameters"
fi

I hope this helps.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNaftalyView Question on Stackoverflow
Solution 1 - BashkonsoleboxView Answer on Stackoverflow
Solution 2 - BashAleks-Daniel Jakimenko-A.View Answer on Stackoverflow
Solution 3 - BashjhvarasView Answer on Stackoverflow
Solution 4 - BashPatView Answer on Stackoverflow
Solution 5 - BashDwight SpencerView Answer on Stackoverflow
Solution 6 - BashjenkizenkiView Answer on Stackoverflow
Solution 7 - BashpanticzView Answer on Stackoverflow
Solution 8 - BashngenetzkyView Answer on Stackoverflow
Solution 9 - BashIsaacEView Answer on Stackoverflow
Solution 10 - BashFabricioView Answer on Stackoverflow