Check number of arguments passed to a Bash script - bash

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?

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
Bash Conditional Expressions
Conditional Constructs
Pattern Matching
Word Splitting
Filename Expansion (prev. Pathname Expansion)
Simple Commands

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.

On []: !=, =, == ... are string comparison operators and -eq, -gt ... are arithmetic binary ones.
I would use:
if [ "$#" != "1" ]; then
Or:
if [ $# -eq 1 ]; then

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

A simple one liner that works can be done using:
[ "$#" -ne 1 ] && ( usage && exit 1 ) || main
This breaks down to:
test the bash variable for size of parameters $# not equals 1 (our number of sub commands)
if true then call usage() function and exit with status 1
else call main() function
Things to note:
usage() can just be simple echo "$0: params"
main can be one long script

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.

Here a simple one liners to check if only one parameter is given otherwise exit the script:
[ "$#" -ne 1 ] && echo "USAGE $0 <PARAMETER>" && exit

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 "$#"

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

You should add spaces between test condition:
if [ $# -ne 1 ];
then echo "illegal number of parameters"
fi
I hope this helps.

Related

Bash:check arguments passed on 'while-case' loop [duplicate]

I need to check the existence of an input argument. I have the following script
if [ "$1" -gt "-1" ]
then echo hi
fi
I get
[: : integer expression expected
How do I check the input argument1 first to see if it exists?
It is:
if [ $# -eq 0 ]
then
echo "No arguments supplied"
fi
The $# variable will tell you the number of input arguments the script was passed.
Or you can check if an argument is an empty string or not like:
if [ -z "$1" ]
then
echo "No argument supplied"
fi
The -z switch will test if the expansion of "$1" is a null string or not. If it is a null string then the body is executed.
It is better to demonstrate this way
if [[ $# -eq 0 ]] ; then
echo 'some message'
exit 1
fi
You normally need to exit if you have too few arguments.
In some cases you need to check whether the user passed an argument to the script and if not, fall back to a default value. Like in the script below:
scale=${2:-1}
emulator #$1 -scale $scale
Here if the user hasn't passed scale as a 2nd parameter, I launch Android emulator with -scale 1 by default. ${varname:-word} is an expansion operator. There are other expansion operators as well:
${varname:=word} which sets the undefined varname instead of returning the word value;
${varname:?message} which either returns varname if it's defined and is not null or prints the message and aborts the script (like the first example);
${varname:+word} which returns word only if varname is defined and is not null; returns null otherwise.
Try:
#!/bin/bash
if [ "$#" -eq "0" ]
then
echo "No arguments supplied"
else
echo "Hello world"
fi
Only because there's a more base point to point out I'll add that you can simply test your string is null:
if [ "$1" ]; then
echo yes
else
echo no
fi
Likewise if you're expecting arg count just test your last:
if [ "$3" ]; then
echo has args correct or not
else
echo fixme
fi
and so on with any arg or var
Another way to detect if arguments were passed to the script:
((!$#)) && echo No arguments supplied!
Note that (( expr )) causes the expression to be evaluated as per rules of Shell Arithmetic.
In order to exit in the absence of any arguments, one can say:
((!$#)) && echo No arguments supplied! && exit 1
Another (analogous) way to say the above would be:
let $# || echo No arguments supplied
let $# || { echo No arguments supplied; exit 1; } # Exit if no arguments!
help let says:
let: let arg [arg ...]
Evaluate arithmetic expressions.
...
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
I often use this snippet for simple scripts:
#!/bin/bash
if [ -z "$1" ]; then
echo -e "\nPlease call '$0 <argument>' to run this command!\n"
exit 1
fi
More modern
#!/usr/bin/env bash
if [[ $# -gt 0 ]]
then echo Arguments were provided.
else echo No arguments were provided.
fi
If you'd like to check if the argument exists, you can check if the # of arguments is greater than or equal to your target argument number.
The following script demonstrates how this works
test.sh
#!/usr/bin/env bash
if [ $# -ge 3 ]
then
echo script has at least 3 arguments
fi
produces the following output
$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
As a small reminder, the numeric test operators in Bash only work on integers (-eq, -lt, -ge, etc.)
I like to ensure my $vars are ints by
var=$(( var + 0 ))
before I test them, just to defend against the "[: integer arg required" error.
one liner bash function validation
myFunction() {
: ${1?"forgot to supply an argument"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add function name and usage
myFunction() {
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add validation to check if integer
to add additional validation, for example to check to see if the argument passed is an integer, modify the validation one liner to call a validation function:
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"
then, construct a validation function that validates the argument, returning 0 on success, 1 on failure and a die function that aborts script on failure
validateIntegers() {
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
return 1 # failure
fi
return 0 #success
}
die() { echo "$*" 1>&2 ; exit 1; }
Even simpler - just use set -u
set -u makes sure that every referenced variable is set when its used, so just set it and forget it
myFunction() {
set -u
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
In my case (with 7 arguments) the only working solution is to check if the last argument exists:
if [[ "$7" == '' ]] ; then
echo "error"
exit
fi

proper way to handle corner cases of parsing command line arguments using case command

I have a bash script which accepts three command line arguments, e.g script is executed like this: script -c <value> -h <value> -w <value>. I would like to ensure that:
order of arguments is not important
if argument does not have a value, then error message is printed
if any of the arguments are missing, then error message is printed
if there are unknown arguments, then error message is printed
I accomplished this with following case statements:
#!/bin/bash
while :; do
case "$1" in
-h)
[[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
host="$2"
shift 2
;;
-w)
[[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
warning="$2"
shift 2
;;
-c)
[[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
critical="$2"
shift 2
;;
"")
[[ $host && $warning && $critical ]] || { echo "One of the arguments is missing!"; exit 1; }
break
;;
*)
echo "Unknow option"
exit 1
;;
esac
done
However, maybe case itself has some advanced options which could avoid all those [[ ]] tests? Or maybe I should use another method altogether for processing command line arguments if I want to make sure that corner cases described above are also covered?
You should ideally use the getopts builtin for this, though there are other ways as well. Getopts is the most portable and legible option, handling all of your "corner cases" pretty much automatically.
while getopts c:h:w: arg; do
case $arg in
( c ) critical="$OPTARG" ;;
( h ) host="$OPTARG" ;;
( w ) warning="$OPTARG" ;;
( \? ) exit 2 ;;
esac
done
shift $((OPTIND-1))
if [ -z "$critical" ] || [ -z "$host" ] || [ -z "$warning" ]; then
echo "One of the arguments is missing!"
exit 1
fi
Each option is followed by a colon, which indicates it has a mandatory argument. If you have a flag that does not use an argument, do not follow the option with a colon. POSIX getopts does not support options with optional arguments.
See also my answer to this question about supporting long options, which merely keys on the - option whose argument is parsed by a nested case switch. Long options implemented in this manner can actually support optional arguments.
I'm a big fan of overloading -h for help. Assuming you have a help function, put this before the getopts loop:
# when the sole argument is -h, provide help
if [ "$*" = "-h" ]; then
help
exit 0
fi

Bash script if statement not working

I'm trying to write a script that adds three specified arguments together, and if there are no arguments outputs: "No arguments".
The trouble is that "No arguments" is always output even when there are three arguments.
I am very new to shell script.
Here is my script:
#!/bin/sh
if [[("$#"==0)]]; then
echo "No arguments specified"
exit 1
fi
sum=0
sum=$(expr $1 + $2 + $3)
echo "$sum"
exit 0
Either change your shebang to #!/bin/bash and use
if (( $# == 0 )); then
or use the POSIX-compatible [:
if [ $# -eq 0 ]; then
Don't forget that [ and [[ are both commands, not syntax, so as with any other command, you need to separate the arguments you pass to the command with spaces.
If you are using bash features, such as [[, you should always use the #!/bin/bash shebang, as otherwise you will run into problems.
As pointed out in the comments below the other answer, it is possibly a better idea to check that you have been passed three arguments:
#!/bin/bash
if (( $# < 3 )); then
echo "Insufficient number of arguments specified"
exit 1
fi
sum=$(( $1 + $2 + $3 ))
echo "$sum"
I have made a couple of other changes to your script, such as not initialising sum to 0 and using the more modern $(( )) to evaluate the sum of the variables.
I guess what you ask for is:
if [ $# -eq 0 ];

How to check that a parameter was supplied to a bash script [duplicate]

This question already has answers here:
Check existence of input argument in a Bash shell script
(12 answers)
Closed 7 years ago.
I just want to check if one parameter was supplied in my bash script or not.
I found this, but all the solutions seem to be unnecessarily complicated.
What's a simple solution to this simple problem that would make sense to a beginner?
Use $# which is equal to the number of arguments supplied, e.g.:
if [ "$#" -ne 1 ]
then
echo "Usage: ..."
exit 1
fi
Word of caution: Note that inside a function this will equal the number of arguments supplied to the function rather than the script.
EDIT: As pointed out by SiegeX in bash you can also use arithmetic expressions in (( ... )). This can be used like this:
if (( $# != 1 ))
then
echo "Usage: ..."
exit 1
fi
The accepted solution checks whether parameters were set by testing against the count of parameters given. If this is not the desired check, that is, if you want to check instead whether a specific parameter was set, the following would do it:
for i in "$#" ; do
if [[ $i == "check parameter" ]] ; then
echo "Is set!"
break
fi
done
Or, more compactly:
for i in "$#" ; do [[ $i == "check argument" ]] && echo "Is set!" && break ; done
if (( "$#" != 1 ))
then
echo "Usage Info:…"
exit 1
fi

Check existence of input argument in a Bash shell script

I need to check the existence of an input argument. I have the following script
if [ "$1" -gt "-1" ]
then echo hi
fi
I get
[: : integer expression expected
How do I check the input argument1 first to see if it exists?
It is:
if [ $# -eq 0 ]
then
echo "No arguments supplied"
fi
The $# variable will tell you the number of input arguments the script was passed.
Or you can check if an argument is an empty string or not like:
if [ -z "$1" ]
then
echo "No argument supplied"
fi
The -z switch will test if the expansion of "$1" is a null string or not. If it is a null string then the body is executed.
It is better to demonstrate this way
if [[ $# -eq 0 ]] ; then
echo 'some message'
exit 1
fi
You normally need to exit if you have too few arguments.
In some cases you need to check whether the user passed an argument to the script and if not, fall back to a default value. Like in the script below:
scale=${2:-1}
emulator #$1 -scale $scale
Here if the user hasn't passed scale as a 2nd parameter, I launch Android emulator with -scale 1 by default. ${varname:-word} is an expansion operator. There are other expansion operators as well:
${varname:=word} which sets the undefined varname instead of returning the word value;
${varname:?message} which either returns varname if it's defined and is not null or prints the message and aborts the script (like the first example);
${varname:+word} which returns word only if varname is defined and is not null; returns null otherwise.
Try:
#!/bin/bash
if [ "$#" -eq "0" ]
then
echo "No arguments supplied"
else
echo "Hello world"
fi
Only because there's a more base point to point out I'll add that you can simply test your string is null:
if [ "$1" ]; then
echo yes
else
echo no
fi
Likewise if you're expecting arg count just test your last:
if [ "$3" ]; then
echo has args correct or not
else
echo fixme
fi
and so on with any arg or var
Another way to detect if arguments were passed to the script:
((!$#)) && echo No arguments supplied!
Note that (( expr )) causes the expression to be evaluated as per rules of Shell Arithmetic.
In order to exit in the absence of any arguments, one can say:
((!$#)) && echo No arguments supplied! && exit 1
Another (analogous) way to say the above would be:
let $# || echo No arguments supplied
let $# || { echo No arguments supplied; exit 1; } # Exit if no arguments!
help let says:
let: let arg [arg ...]
Evaluate arithmetic expressions.
...
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
I often use this snippet for simple scripts:
#!/bin/bash
if [ -z "$1" ]; then
echo -e "\nPlease call '$0 <argument>' to run this command!\n"
exit 1
fi
More modern
#!/usr/bin/env bash
if [[ $# -gt 0 ]]
then echo Arguments were provided.
else echo No arguments were provided.
fi
If you'd like to check if the argument exists, you can check if the # of arguments is greater than or equal to your target argument number.
The following script demonstrates how this works
test.sh
#!/usr/bin/env bash
if [ $# -ge 3 ]
then
echo script has at least 3 arguments
fi
produces the following output
$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
As a small reminder, the numeric test operators in Bash only work on integers (-eq, -lt, -ge, etc.)
I like to ensure my $vars are ints by
var=$(( var + 0 ))
before I test them, just to defend against the "[: integer arg required" error.
one liner bash function validation
myFunction() {
: ${1?"forgot to supply an argument"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add function name and usage
myFunction() {
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add validation to check if integer
to add additional validation, for example to check to see if the argument passed is an integer, modify the validation one liner to call a validation function:
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"
then, construct a validation function that validates the argument, returning 0 on success, 1 on failure and a die function that aborts script on failure
validateIntegers() {
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
return 1 # failure
fi
return 0 #success
}
die() { echo "$*" 1>&2 ; exit 1; }
Even simpler - just use set -u
set -u makes sure that every referenced variable is set when its used, so just set it and forget it
myFunction() {
set -u
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
In my case (with 7 arguments) the only working solution is to check if the last argument exists:
if [[ "$7" == '' ]] ; then
echo "error"
exit
fi

Resources