74

I am running some script which passing the string argument and I want to do if else statement shown as below:

if [ $1 != '' ] && [ $2 != '' ]
then 
    do something.....

but it shown Error too many argument. Why?

4
  • You should provide 1. the command which you call the script and 2. the full output.
    – Lucio
    Apr 7, 2014 at 3:46
  • 4
    You should use [[ ]]. Otherwise you have to quote your variables. Jan 8, 2015 at 22:48
  • If $1 didn't exist then $2 would become $1 which makes the test of $1 and $2 both being null seem irrelevant. Dec 25, 2016 at 2:18
  • @WinEunuuchs2Unix Not necessarily irrelevant - in some cases you want to ensure there's actually something instead of blank or null string in arguments. $1 could be unset or set to null string by user of the script. Consider this sequence of command: $ set '' bar then echo "x${1}x"; Both variables are set, but one of them is null. Dec 3, 2018 at 5:54

5 Answers 5

96

Try using the -z test:

if [ -z "$1" ] && [ -z "$2" ]

From man bash:

-z string
   True if the length of string is zero.
1
  • 1
    When writing portable shell scripts, this flag should be used with care, since on certain commercial Unixes this flag is faulty. See my answer for linked sources. Dec 3, 2018 at 5:50
20

Since this is tagged bash, I recommend that one use the extended test construct ([[...]]), and forget the quotes:

if [[ -z $1 && -z $2 ]]; then
...

Unless you are going for sh/POSIX compatibility, there is no reason not to use [[ ]].

6

The following also works,

if [ "$1" == "" && "$2" == ""]; then
    echo NULL
fi
1
  • The && and other logical command separators are not allowed in the classic test. You have to use other test constructs instead (like -a, I think)
    – muru
    Sep 21, 2014 at 13:41
4

For the old version of the answer, see the second portion of this answer. If you want to know about details, read on

The cause of issue

In the question itself, it is reported that OP sees too many arguments error, which when tested in bash doesn't seem to be the case:

$ [ $1 != '' ] && [ $2 != '' ]
bash: [: !=: unary operator expected

With /bin/sh which is actually symlinked to /bin/dash on Ubuntu, error reported as follows:

$ sh
$ [ $1 != '' ] && [ $2 != '' ]
sh: 1: [: !=: unexpected operator

And the standalone /bin/test also :

$ /usr/bin/test $1 != ''  
/usr/bin/test: missing argument after ‘’

Sidenote: If you're wondering what is /usr/bin/test and why I'm using bash and sh, then you should know that [ is alias for test command, which also exists as standalone executable or more commonly - as shell built-in which is what each shell will use first. As for if statements, they operate on exit statues of commands, hence why [ and test are commands, with everything else being arguments to that commands - improper order of those command-line args leads to errors.

Back to the topic: it's unclear how OP got the unrelated error. However, in all 3 cases the issue is the same - unset variable will be treated as empty, thus what the shell sees with these unquoted variables is

[ != '' ]

which breaks syntax which test understands. Remember what I said about improper order of command-line arguments ? Hence why quoting is important. Let's enable diagnostic output and see what shell executes:

$ set -x
# throws error
$ [ $1 != '' ] && [ $2 != '' ] 
+ '[' '!=' '' ']'
bash: [: !=: unary operator expected
# no error
$ [ "$1" != '' ] && [ "$2" != '' ] || echo null vars
+ '[' '' '!=' '' ']'
+ echo null vars
null vars

Better way to test unset variables

A very frequent approach that you see around is this:

 if [ "x$var1" == "x"  ] && [ "x$var2" == "x"  ];                                                                
 then
     echo "both variables are null"
 fi

To quote Gilles:

In [ "x$1" = "x" ], the x prefix ensures that x"$1" cannot possibly look like an operator, and so the only way the shell can parse this test is by treating = as a binary operator.

Presumably, this should be fairly portable since I've seen these in /bin/sh scripts. It also can be combined as in

if [ "x${var1}${var2}" == "x" ]; then
    ...
fi

Of course we could use -z flag, however according to research in some shells, particularly ksh88 (according to Stephane Chazelas), this flag is faulty.

See also

1
  • This should be the right answer, this approach resolves two variables conditions at the same time. Excellent details, and thanks I learned something
    – Lyoneel
    Mar 30, 2022 at 16:19
3

I think the title of the post is not accurate, as the intention in the message was to check if $1 and $2 are not null. The given example was just missing double quotes in $1 and $2 to work. Variables must be double quoted to be expanded when comparing strings. But, to check if $1 and $2 exist is the same as check if $2 exist, as it can't exist if $1 doesn't. The 'if' command is also not needed in this case, as 'test' returns true/false and uses '&&' as 'then' if return is 0/true:

[ "$2" != '' ] && commands...

Simpler, with -n (nonzero):

[ -n "$2" ] && commands...

To "check if $1 and $2 are null" would be the same as check if there is no parameter:

[ $# -eq 0 ] && commands...

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .