Say I have a executable bash file script.sh.

I want to use it as

./script.sh p1 p2

p1 and p2 are two necessary parameters for this command. If either one of them is missing, the command should fail.

So I need to check them before go on executing further in script.sh. How could I check both of them are set?


I tried this:

# this is a comment line
if [ -n "$1" ] || [ -n "$2" ]; then
    then echo 'haha'

but got:

./_scp.sh: line 3: syntax error near unexpected token `then'
./_scp.sh: line 3: `    then echo 'haha''
  • 3
    You have two then, and missing last ;, you only need if [ -n "$1" ] || [ -n "$2" ]; then echo 'haha'; fi – cuonglm Apr 4 '15 at 3:26

In POSIX shell, if you only want to check two parameters was set, try:

if [ "$#" -lt 2 ]; then
  echo 'Need 2 parameter'
  exit 1

If you want two parameters aren't empty:

if [ -z "$1" ] || [ -z "$2" ]; then
  echo 'Need 2 parameter are not empty'
  exit 1

With bash (and ksh), you can use:

[ -v var ] && echo var was set

to check whether variable var was set or not.

$ [ -v var ] && echo var was set
$ var=
$ [ -v var ] && echo var was set
var was set
  • what is the difference of -z and -n? Thanks! – AGamePlayer Apr 4 '15 at 3:15
  • Would you please take a look at my edited question? thanks! – AGamePlayer Apr 4 '15 at 3:18
  • @AwQiruiGuo: -n test if length is non-zero, -z test if length is zero. I made a comment. – cuonglm Apr 4 '15 at 3:27

You can make them fail the script:

: "${2:?} ${1:?}"
#If either one of the above is unset or null the 
#script will have already exited with a meaningful
#diagnstic message written to standard error.

The shell exits with error and the message is generated automatically: exactly what it says is shell dependent, but it usually looks like this:

(set --; ${1:?})
sh: 2: 1: parameter not set or null

...where first_colon_delimited_field: is $0, next is $LINENO; followed by var_name, and finally diagnostic message. You've probably seen similar messages in the past.

You can get specific about the diagnostic message:

(set --; ${1:?Hi there!})
sh: 3: 1: Hi there!

Also, it's an inline, implicit test. If the targeted parameters are set and not null (or possibly null if you drop the :colon from :? the parameter expansion syntax), they expand normally:

(set param; echo "${1:?This better not be empty!}")

And this, like other forms of modifying parameter expansions, can be applied to other types of parameters than just your positionals:

param= bash -c '
    printf "Sure hope this works...\n" "${param:?Not a chance!}"
    echo ... but what about me\?
'   newzero
echo "RETURN: $?"

...which prints to my terminal...

newzero: line 1: param: Not a chance!

The optional diagnostic message is itself an expansion - whatever it expands to is what the shell will write out to stderr. I almost always use it for the --help message when I add option parsing to a script. I just make a little function and pass it the numbered parameter I expected when I encounter an issue:

#script and more script
help(){ eval "\${$param:?\$(cat)}"; } <<HELP
Usage [ and the usual ... ]

while getopts ....
do    case $opt in ($myopts) :;;
      (*) param=$OPTIND help;;esac
  • My bad when forgetting this standard way. – cuonglm Apr 4 '15 at 3:31
  • @cuonglm - It's not as standard as test - you've got my vote already. I just like that you can make stuff blow up with a brace or two. – mikeserv Apr 4 '15 at 3:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.