Check existence of input argument in a Bash shell script - bash

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

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

Korn conditional operator not working

I wrote a small korn script, but when I try to run the script, it will not echo the message I want to display. When I try to run it by
ksh script.sh -1
it is not echoing the message.
if [ $# -le 0 ]
then
echo "That is a negative integer!"
exit
fi
In bash/ksh $# represents the number of arguments passed as parameters.
What you needed is
if [ ${1:-0} -lt 0 ] # $1 is the first parameter
then
echo "That is a negative integer!"
exit
fi
Or a shorted version of the above
[ ${1:-0} -lt 0 ] && echo "That is a negative integer!" && exit
Edit 1
I have used shell [ parameter expansion ] ${1:-0} supply a default value.
Since zero is technically not a negative number, replace -le with -lt
Edit 2
If you're looking forward to match a particular string then do below
[ ${1:-NULL} = "StringToMatch" ] && DoSomething
If you're looking to see if the output is just has atleast one non-digit character,then do something like below
[[ {1:-NULL} =~ [^[:digit:]]+ ]] && DoSomething
Warning : Not all expansions mentioned in the link may not be supported by ksh

Check number of arguments passed to a Bash script

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.

How can I test whether a positional parameter is set in Bash?

I wonder why the test [[ ! -v 1 ]] fails no matter if I pass the 1st positional parameter to the function below:
shopt -os nounset
function foo {
echo -n "$FUNCNAME: 1st positional parameter "
[[ ! -v 1 ]] && echo "is missing." || echo is "\"$1\"."
}
I know there are other ways to test but why doesn't this particular test work?
In this case, you want to check if the parameter is unset.
has_1() {
if [[ -z "${1+present}" ]]; then
echo "no first param"
else
echo "given: $1"
fi
}
The parameter expansion ${var+word} will return "word" only if the parameter is not unset -- i.e. if you pass an empty string, the function will indicate the first parameter is given.
Bash 5.1 has a very straight-forward way to do this. As described in the release notes:
x. `test -v N' can now test whether or not positional parameter N is set.
So to check if the Nth parameter is set can use either of these:
test -v N
[ -v N ]
See a very basic example:
test -v 1 && echo "1st parameter is set: '$1'"
[ -v 2 ] && echo "2nd parameter is set: '$2'"
See some samples:
bash-5.1$ bash script.sh ""
1st parameter is set: ''
bash-5.1$ bash script.sh a b
1st parameter is set: 'a'
2nd parameter is set: 'b'
bash-5.1$ bash script.sh ""
1st parameter is set: ''
bash-5.1$ bash script.sh "" bla
1st parameter is set: ''
2nd parameter is set: 'bla'
if [ "$#" -gt "0" ]; then echo 'ok'; else echo '0'; fi
The following pattern covers most of the practical use cases:
[[ -z "${2:-}" ]] && echo "The 2'nd parameter is unset" >&2 && exit 1
Shell-Parameter-Expansion

Shell script elif

I am new in shell script, trying to catch the return value of a program, and do something with it.
I have this script below
#!/bin/sh
if [ $# !=2 ] ; then
echo "Usage : param1 param2 "
exit 1;
elif [ $# -eq 2 ]; then
./callprogram
$out = $?
echo "$out"
fi
if [ $out==0 ]; then
echo "out ok"
fi
It keeps getting me error of
"[: 11: 0: unexpected operator
out ok
I have no clue why line 11 is wrong. if I remove "fi", it will promt that it needs "fi". Can anyone help with this matter?
Thank you
You need a space after the [ and you need to use -eq (equals) or -ne (not equals) to compare numbers in your if-statement.
To assign a variable use out=$?, not $out = $?. There should be no spaces on either side of the = sign.
Try this:
if [ $# -ne 2 ] ; then
echo "Usage : param1 param2 "
exit 1
elif [ $# -eq 2 ]; then
./callprogram
out=$?
echo "$out"
fi
if [ $out -eq 0 ]; then
echo "out ok"
fi
Change:
if [ $out==0 ]; then
to:
if [ $out = 0 ]; then
add spaces, and change '==' to '='. Note, that bash, executed as a bash accepts ==. But if you run is as a sh it will say "unexpected operator".
Why:
The [ is a command (or symlink to test binary, depending on your OS and shell). It expects $out and == and 0 and ] to be separate command arguments. If you miss the space around them, you have one argument $out==0.
BTW:
It's safer to always enquote the variables like that:
if [ "$var" ......
instead of
if [ $var
because when variable is empty, then you can get another error because of wrong number of arguments (no argument instead of empty string).
You have several problems. The one that is giving you the error is that you need a space after != on
if [ $# != 2 ]
(although -ne would be better than !=). It appears that you are calling the script with 11 arguments, and then calling [ with the arguments 11 !=2, and it does not know what to do with !=2 because you meant != 2 but forgot the space. Also, you want
out=$?
on the assignment (no $ on the LHS)
and
if [ $out = 0 ]
on the comparison. (Spaces around the operator, which is '=' instead of '=='. '==' will work on many shells, but '=' works in more shells.)
But your script would be better written without the explicit reference to $?
#!/bin/sh
if test $# != 2; then
echo "Usage: $0 param1 param2 " >&2 # Errors go to stderr, not stdout
exit 1;
fi
# you know $# is 2 here. No need to check
if ./callprogram; then
echo "out ok"
fi

Resources