Linux unary operator expected

-eq: unary operator expected [closed]

Why I am getting -eq: unary operator expected when executing above? A more complete version of what I am doing:

for file in `cat $` #$2 is file.txt do if [ ! -f "$/$" ]; # $1 is a path then echo "$file is missing" notok=$? fi done if [ $ -eq 0 ]; then echo "need to check" exit 1 else echo "All files present" fi

From the script JdeBP edited in from the comment, it should be easy to see why notok can be unset in some cases, so IMO this just falls back to the lack of quoting

4 Answers 4

It look like variable x is undefined.

where $ will evaluated to $x ‘s value if defined or 1 if not.

or better, I assume there is a command before x=$? , why not use

if cmd arg1 . argn then # true else # false fi 

@deepak – this is because x does not contain a value. Is there a command before your snippet? $? Contains exit status for last command. Where is your last command? This is the second time someone asked you to no response. Help us help you!,

@deepak – also, questions typically have question marks ( ? ). Maybe your question should be: Does anyone have time to write a script for me? If your question is Why I am getting -eq: unary operator?, then you got your answer over an hour ago (just scroll up). best of luck!

for file in cat $ <2>——$2 is file.txt do if [ ! -f «$/$» ];———$1 is a path then echo «$file is missing» notok=$? fi done if [ $ -eq 0 ]; then echo «need to check» exit 1 else echo «All files present» fi [Here when notok is not qual to zero , then it should give as all files present but it does so along with error -eq: unary operator expected ]

That sort of stuff should have been in the question from the start and should not be buried in a comment on an answer.

Ok, now that you’ve edited your question, I think I know what is really happening.

Let’s assume I have a directory ( ~/dir ) which contains some files and a text file ( ~/file.txt ) which contains some filenames:

$ ls ~/dir 1.txt 2.txt 3.txt 4.txt 5.txt $ cat ~/file.txt 1.txt 2.txt 3.txt 4.txt 5.txt 

As far as I know, your script reads the content of ~/file.txt and checks if those files ( 1.txt , 2.txt , etc.) exists inside of ~/dir .

$ script.sh ~/dir ~/file.txt /home/user/bin/script.sh: line 11: [: -eq: unary operator expected All files present 

So, what’s happening? Look at this excerpt of code:

if [ ! -f "$/$" ]; # $1 is a path then echo "$file is missing" notok=$? fi 

The main flaw here is that if the content of both ~/dir and ~/file.txt matches, the echo «$file is missing»; notok=$? never gets executed. Then, if the notok variable holds no value, [ $ -eq 0 ] fails because $ expands to nothing (as many of us suspected).

That flaw is not the only one, but it’s the reason why you are getting the [: -eq: unary operator expected error.

Читайте также:  Remove directory in terminal linux

How do you solve it?

If you don’t want to rewrite your script, just initialize the notok variable with any number different from 0 before your main code. For example:

notok='1' for file in `cat $` #$2 is file.txt do if [ ! -f "$/$" ]; # $1 is a path then echo "$file is missing" notok=$? fi done if [ $ -eq 0 ]; then echo "need to check" exit 1 else echo "All files present" fi 
# When the content of ~/dir and ~/file.txt matches $ ls ~/dir 1.txt 2.txt 3.txt 4.txt 5.txt $ cat ~/file.txt 1.txt 2.txt 3.txt 4.txt 5.txt $ script.sh ~/dir ~/file.txt All files present # When the content of ~/dir and ~/file.txt does not match $ ls ~/dir 1.txt 2.txt 3.txt 4.txt 5.txt $ cat ~/file.txt foo 1.txt 2.txt 3.txt 4.txt 5.txt $ script.sh ~/dir ~/file.txt foo is missing need to check 

But if I were to rewrite the script, I’d do something like this:

# Initialize variables # It's possible to parse arguments like `-d DIR -f FILE` but let's keep simple dir="$" txt="$" missing='0' # Don't read lines with for! while IFS='' read -r 'file'; do if [ ! -f "$/$" ]; then echo "Missing file: $" # Use a simple counter instead of catch the exit code of `echo` missing=$(( missing + 1 )) fi done < "$" if [ "$" -gt '0' ]; then echo "Total: $" exit '1' else echo 'All files are present' fi 

@deepak The redirection < "$" tells the while loop to read data from the file whose name is in the variable $ . If you ever need to read files line-by-line, it's recommendable to use a while loop instead of a for loop.

I think what you really want here is rsync :

rsync --list-only --files-from="$2" "$1" "$1/.." 

The last argument is a dummy argument but is necessary; it could be any directory so long as it's not the same directory as $1 itself.

Alternatively, if all you want is the exit status and less verbosity:

rsync --dry-run --files-from="$2" "$1" "$1/.." 

(Optionally add 2>/dev/null on the end, if you really only want the exit status.)

Now, for a review of the broken script you posted:

for file in `cat $` #$2 is file.txt 

You're assuming that the filename passed in $2 doesn't have any spaces or special characters in its name; see Why does my shell script choke on whitespace or other special characters?

You're also assuming that all files listed in $2 don't have any special characters or whitespace in their names.

And you're assuming that the list is short enough that it won't exceed your shell's maximum length for an argument list. If the list contains wildcards (e.g. /*/*/*/*/../../../../*/*/*/* ) then you will have lots and lots of problems.

Do you really only want regular files to be allowed? And not special files of any kind, and not even directories? If so then you may need to revise the rsync command given earlier.

Also, stylistic point: putting the ! before the [ as in if ! [ -f "$1/$file" ] is less likely to lead you astray. Nothing wrong with it in this specific case, however. (If you combine [ ! . ] with missing double quotes you are very likely to be led astray.)

 then echo "$file is missing" notok=$? 

Unless the echo command fails, you're setting notok to 0 here in every case.

Читайте также:  Creating virtual machine in linux

This is even sillier when you realize that you've already checked the exit status. You don't need to do so again. If you wrote notok=1 here (and added notok=0 to the top of your script) you would get a simpler and better form.

Missing double quote characters. Again, see Why does my shell script choke on whitespace or other special characters? (and note its subtitle "an introductory guide to robust filename handling and other string passing in shell scripts").

This message makes absolutely no sense. Need to check what? Who needs to check what? Huh?

 exit 1 else echo "All files present" fi 

Replacement script

if rsync --dry-run --files-from="$2" "$1" "$1/.." 2>/dev/null; then echo "All files present" else echo "need to check" exit 1 fi 

Replacement script that disallows directories in list (will throw an error on them)

if ! rsync --dry-run --files-from="$2" "$1" "$1/.." --no-dirs 2>&1 | grep -q .; then echo "All files present" else echo "need to check" exit 1 fi 

Источник

Bash script error [: !=: unary operator expected

In my script I am trying to error check if the first and only argument is equal to -v , but it is an optional argument. I use an if statement, but I keep getting the unary operator expected error. This is the code:

if [ $1 != -v ]; then echo "usage: $0 [-v]" exit fi 

To be more specific: This part of the script above is checking an optional argument and then after, if the argument is not entered, it should run the rest of the program.

#!/bin/bash if [ "$#" -gt "1" ]; then echo "usage: $0 [-v]" exit fi if [ "$1" != -v ]; then echo "usage: $0 [-v]" exit fi if [ "$1" = -v ]; then echo "`ps -ef | grep -v '\['`" else echo "`ps -ef | grep '\[' | grep root`" fi 

. by the way, I think you want echo "usage: $0 [-v]" ; $- shows the active shell option flags, not the name of the current script.

Welcome to stackoverflow, and to the bash tag in particular! Check out the tag wiki for useful tools and resources, like shellcheck which will point out (though not always explain) many issues like this.

2 Answers 2

Otherwise, when $1 is completely empty, your test becomes:

. and != is not a unary operator (that is, one capable of taking only a single argument).

Or, if you're not concerned about portability, you can use double brackets, inside of which variable expansions need not be quoted: if [[ $1 != -v ]]; then

@DanielDinnyes, if IFS=1 , then [ $# -eq 1 ] won't behave so well, whereas [ "$#" -eq 1 ] behaves as-intended even then. It's a pathological case, sure, but better to write software that doesn't have 'em when given the choice.

Or for what seems like rampant overkill, but is actually simplistic . Pretty much covers all of your cases, and no empty string or unary concerns.

In the case the first arg is '-v', then do your conditional ps -ef , else in all other cases throw the usage.

#!/bin/sh case $1 in '-v') if [ "$1" = -v ]; then echo "`ps -ef | grep -v '\['`" else echo "`ps -ef | grep '\[' | grep root`" fi;; *) echo "usage: $0 [-v]" exit 1;; #It is good practice to throw a code, hence allowing $? check esac 

If one cares not where the '-v' arg is, then simply drop the case inside a loop. The would allow walking all the args and finding '-v' anywhere (provided it exists). This means command line argument order is not important. Be forewarned, as presented, the variable arg_match is set, thus it is merely a flag. It allows for multiple occurrences of the '-v' arg. One could ignore all other occurrences of '-v' easy enough.

#!/bin/sh usage () < echo "usage: $0 [-v]" exit 1 >unset arg_match for arg in $* do case $arg in '-v') if [ "$arg" = -v ]; then echo "`ps -ef | grep -v '\['`" else echo "`ps -ef | grep '\[' | grep root`" fi arg_match=1;; # this is set, but could increment. *) ;; esac done if [ ! $arg_match ] then usage fi 

But, allow multiple occurrences of an argument is convenient to use in situations such as:

$ adduser -u:sam -s -f -u:bob -trace -verbose 

We care not about the order of the arguments, and even allow multiple -u arguments. Yes, it is a simple matter to also allow:

$ adduser -u sam -s -f -u bob -trace -verbose 

Источник

Читайте также:  Xerox 3250 драйвер linux ppd

Compare integer in bash, unary operator expected

Your problem arises from the fact that $i has a blank value when your statement fails. Always quote your variables when performing comparisons if there is the slightest chance that one of them may be empty, e.g.:

This is because of how the shell treats variables. Assume the original example,

The first thing that the shell does when executing that particular line of code is substitute the value of $i , just like your favorite editor's search & replace function would. So assume that $i is empty or, even more illustrative, assume that $i is a bunch of spaces! The shell will replace $i as follows:

Now that variable substitutions are done, the shell proceeds with the comparison and. fails because it cannot see anything intelligible to the left of -gt . However, quoting $i :

The shell now sees the double-quotes, and knows that you are actually comparing four blanks to 2 and will skip the if .

You also have the option of specifying a default value for $i if $i is blank, as follows:

This will substitute the value 0 instead of $i is $i is undefined. I still maintain the quotes because, again, if $i is a bunch of blanks then it does not count as undefined, it will not be replaced with 0, and you will run into the problem once again.

Please read this when you have the time. The shell is treated like a black box by many, but it operates with very few and very simple rules - once you are aware of what those rules are (one of them being how variables work in the shell, as explained above) the shell will have no more secrets for you.

Источник

Оцените статью
Adblock
detector