LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 05-26-2011, 02:27 AM   #1
hd_pulse
Member
 
Registered: Dec 2010
Posts: 35

Rep: Reputation: 0
unary operator expected


I am trying to find the output of the following code :

Code:
i=4 j=-1  k=0
[ $i -o $j -o $k ]
echo $?
[ $i -a $j -a $k ]
echo $?
[ $i -a $j -o $k ]
echo $?
But it generates an error as :
./10aj: line 4: [: -1: unary operator expected
2
./10aj: line 6: [: -1: unary operator expected
2
./10aj: line 8: [: -1: unary operator expected
2

where am I making mistake??

what unary operator is 'shell' talking about?
 
Old 05-26-2011, 06:41 AM   #2
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Wheezy (Fluxbox WM)
Posts: 1,363
Blog Entries: 52

Rep: Reputation: 353Reputation: 353Reputation: 353Reputation: 353
The script expression has a boolean operator. After the operator, it expects to see a boolean expression. A boolean expression could be either a boolean value, or a more complex expression beginning with a unary operator. Since '-1' cannot be evaluated as a boolean value, it looks for a unary operator. When that fails, it gives the appropriate syntax error.

I'm not sure what you are trying to do. Perhaps you are trying to check if the value is non-zero?
 
Old 05-26-2011, 06:53 AM   #3
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,561

Rep: Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939
Maybe you were trying to do:
Code:
#!/bin/bash

i=4
j=-1
k=0

(( i || j || k )) && echo line 1 $?
(( i && j && k )) && echo line 2 $?
(( i && j || k )) && echo line 3 $?
I added line number so we could tell what was true
 
Old 05-26-2011, 07:54 AM   #4
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
Also, doesn't the dash before the number make test think that it's an option? Or can it somehow figure out that it means "negative"?
 
Old 05-26-2011, 07:58 AM   #5
crts
Senior Member
 
Registered: Jan 2010
Posts: 1,604

Rep: Reputation: 446Reputation: 446Reputation: 446Reputation: 446Reputation: 446
Quote:
Originally Posted by neonsignal View Post
The script expression has a boolean operator. After the operator, it expects to see a boolean expression. A boolean expression could be either a boolean value, or a more complex expression beginning with a unary operator. Since '-1' cannot be evaluated as a boolean value, it looks for a unary operator. When that fails, it gives the appropriate syntax error.

I'm not sure what you are trying to do. Perhaps you are trying to check if the value is non-zero?
Hi,

I got used to evaluating expressions like this
Code:
[[ $i || $j || $k ]]
which works fine. However, this thread got me curious and I experimented with the expressions in the OP. So either I am missing something very fundamental about the '-o' and '-a' operators or there is another inconsistency in bash (or in the implementation of '[').
Code:
[ 4 -a -1 -a 0 ] # this returns an error
[ 4 -a -10 -a 0 ] #this, however, is OK
So my first thought was, the '[' implicitly assumes the '-n' if it sees something like
Code:
[ 4 ] # implicitly assumes [ -n 4 ]
So an expression like
Code:
[ 4 -a 0 -a 3]
will implicitly be handled like
Code:
[ -n 4 -a -n 0 -a -n 3]
In case you do not want to test for a nonzero string by default you should be able to pass another unary operator like -z. Now '[' needs to determine if the token after '-a' is an operator which overrides the default. The decision if the next token is an operator is based upon if the first character is a minus '-' and if the token has length 2. If one of those conditions is not met then '[' determines that the token is not an operator. Observe:
Code:
$ [ 4 -a -1 -a 0 ] && echo true || echo false
bash: [: -1: unary operator expected
false
$ [ 4 -a -10 -a 0 ] && echo true || echo false
true
$ [ 4 -a -n -1 -a 0 ] && echo true || false
true
$ [ 4 -a -z -1 -a 0 ] && echo true || echo false
false
I consider not evaluating the second character of the second token to determine if it is an operator as inconsistency. Maybe even a bug?
Well, that is my theory so far. But it gets even stranger:
Code:
$ [ -1 ] && echo true || echo false
true
$ [ 0 -a -1 ] && echo true || echo false
true
Why is it handling it correctly when there is only one '-a' operator involved? My guess would be, that the whole expression is parsed and rearranged to account for operator precedence. Something must go wrong while it is parsed.

I had a quick look at the manpage but did not find anything that explains this behavior. Did I overlook something?

Other opinions/explanations of the observed behavior are welcome.
 
Old 05-26-2011, 11:05 AM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,561

Rep: Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939
Well interestingly if you use [[]] you get perhaps more informative error messages:
Code:
./d.sh: line 3: conditional binary operator expected
./d.sh: line 3: syntax error near `-a'
./d.sh: line 3: `[[ 4 -a -1 -a 0 ]] && echo true'
It appears that test, [ or [[ perceives any single character after a dash as an option and only once the single number is adjoined to another number
does it then become a negative. I am not sure I would call it a bug as perhaps how you would program around this??
 
Old 05-26-2011, 01:21 PM   #7
crts
Senior Member
 
Registered: Jan 2010
Posts: 1,604

Rep: Reputation: 446Reputation: 446Reputation: 446Reputation: 446Reputation: 446
Quote:
Originally Posted by grail View Post
Well interestingly if you use [[]] you get perhaps more informative error messages:
Yes, I tried that. I am not sure if the parsing mechanism is the same as with '['. But the behavior of '[[' differs:
Code:
$ [[ 1 -a 3 -a 4 ]] && echo true || echo false
bash: conditional binary operator expected
bash: syntax error near `-a'
$ [ 1 -a 3 -a 4 ] && echo true || echo false
true
So I'd like to focus on '[' before tackling '[['.

I found the section in bash man-page that describes the intended behavior of '['"
Code:
       test expr
       [ expr ]
              Return  a  status of 0 or 1 depending on the evaluation of the conditional expres‐
              sion expr.  Each operator and operand must be a  separate  argument.   Expressions
              are composed of the primaries described above under CONDITIONAL EXPRESSIONS.  test
              does not accept any options, nor does it accept and ignore an argument  of  --  as
              signifying the end of options.

              Expressions  may  be  combined using the following operators, listed in decreasing
              order of precedence.  The evaluation depends  on  the  number  of  arguments;  see
              below.
              ! expr True if expr is false.
              ( expr )
                     Returns  the value of expr.  This may be used to override the normal prece‐
                     dence of operators.
              expr1 -a expr2
                     True if both expr1 and expr2 are true.
              expr1 -o expr2
                     True if either expr1 or expr2 is true.

              test and [ evaluate conditional expressions using a set of rules based on the num‐
              ber of arguments.

              0 arguments
                     The expression is false.
              1 argument
                     The expression is true if and only if the argument is not null.
              2 arguments
                     If  the first argument is !, the expression is true if and only if the sec‐
                     ond argument is null.  If the first argument is one  of  the  unary  condi‐
                     tional operators listed above under CONDITIONAL EXPRESSIONS, the expression
                     is true if the unary test is true.  If the first argument is  not  a  valid
                     unary conditional operator, the expression is false.
              3 arguments
                     If  the  second  argument is one of the binary conditional operators listed
                     above under CONDITIONAL EXPRESSIONS, the result of the  expression  is  the
                     result  of the binary test using the first and third arguments as operands.
                     The -a and -o operators are considered  binary  operators  when  there  are
                     three  arguments.  If the first argument is !, the value is the negation of
                     the two-argument test using the second and third arguments.  If  the  first
                     argument  is  exactly  ( and the third argument is exactly ), the result is
                     the one-argument test of the second argument.  Otherwise, the expression is
                     false.
              4 arguments
                     If  the  first argument is !, the result is the negation of the three-argu‐
                     ment expression  composed  of  the  remaining  arguments.   Otherwise,  the
                     expression  is parsed and evaluated according to precedence using the rules
                     listed above.
              5 or more arguments
                     The expression is parsed and evaluated according to  precedence  using  the
                     rules listed above.
Now let's have a look at the intended behavior when there are three arguments:
Code:
$ [ 1 -a -1 ] && echo true || echo false
true
'[' sees three arguments and that the second argument is the binary operator '-a'. According to the man-page it determines that the first argument and the second argument must be operands and thus treated as such.

To further verify that the second argument is decisive for its behavior when there are three arguments passed, consider the following:
Code:
# According to the man-page '-a' can also be a unary operator:
#       -a file
#              True if file exists.
$ ls
file
$ [ ! -a file ] && echo true || echo false
true
The fact that there are three arguments determines that '-a' has to be the binary operator. Hence, '!' is not treated as the negation operator but simply as string. So we can not use this construct to test if a file is present and then negate the outcome. To do this we have to change the order in which the expression is being evaluated. This can be done with braces:
Code:
$ ls
file
$ [ ! \( -a file \) ] && echo true || echo false
false
According to the five-arguments-rule the braces cause to evaluate the expression inside them first which results in '-a' being interpreted according to the two-arguments-rule as unary operator.
More fun with unary operators:
Code:
$ ls
file
$ [ 1 -a -a file ] && echo true || echo false
true
$ [ 1 -a -a nofile ] && echo true || echo false
false
Unary operator '-a' takes precedence over binary '-a' if there are more than three arguments. According to the four-argument-rule the above first evaluates '-a file' according to the two-rule-argument and the result according to the three-rule-argument.

According to the five-or-more-rule the following should have worked:
Code:
$ [ \( 1 -a -1 \) -a 4 ] && echo true
bash: [: -1: unary operator expected
$ [ 1 -a \( -1 -a 4 \) ] && echo true
bash: [: -1: unary operator expected
At least with braces the expr. within should have been evaluated according to the three-argument-rule. Therefore it should have determined that '-a' is a binary operator and treat '-1' as operand. Enclosed within braces, there should be no confusion about misinterpreting '-1' as unary operator.
Apparently, this is not the case.

After all, I am more and more inclined to consider this behavior as a bug. Or is my logic failing me?

Last edited by crts; 05-26-2011 at 07:51 PM. Reason: formatting
 
Old 05-26-2011, 07:43 PM   #8
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Wheezy (Fluxbox WM)
Posts: 1,363
Blog Entries: 52

Rep: Reputation: 353Reputation: 353Reputation: 353Reputation: 353
I don't quite see the problem. The original post is using '-a' operators with numbers, but they are intended to be used with conditional values. I'll agree that the error message is not very informative, but the only surprising thing is how lenient the shell is.
Code:
[ 0 -a 0 ] && echo true || echo false
true
[ -0 -a -0 ] && echo true || echo false
true
[ "" -a "" ] && echo true || echo false
false
If the intention is to check the values, then comparisons can be used, and it all works (or better still, use double parentheses as grail suggests).
Code:
[ 4 -ne 0 -o -1 -ne 0 -o 0 -ne 0 ] && echo true || echo false
true
[ 4 -ne 0 -a -1 -ne 0 -a 0 -ne 0 ] && echo true || echo false
false

Last edited by neonsignal; 05-26-2011 at 07:49 PM.
 
Old 05-26-2011, 11:01 PM   #9
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: Debian lenny, Slackware 12
Posts: 809

Rep: Reputation: 178Reputation: 178
Code:
./10a line 4: [: -1: unary operator expected
Nobody expects the unary operator.

That is all.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] String comparison - [: =: unary operator expected hattori.hanzo Programming 2 11-23-2010 07:55 PM
error: unary operator expected ?? Lynda_M Programming 3 11-29-2008 08:03 PM
unary operator expected error! Lynda_M Programming 3 11-29-2008 12:04 PM
unary operator expected MONKEYJUDO Linux - Newbie 1 07-13-2008 06:05 AM
Unary Operator expected. Bash script Blackout_08 Programming 2 06-22-2006 02:21 PM


All times are GMT -5. The time now is 09:22 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration