Shell Script logical operator for conditions - shell

$i="500,600"
$j="600"
if[$i -ne $j]; then
#some line
else
#some line
fi
This if condition is not going inside.
this if condition fails. else is pass.
how is this possible
can someone help me on this

The trick is to consider the "[" sign as a command (in fact it is one indeed), whose last argument must be a "]". So you must ensure that there is a space after [ and all of its arguments go to the proper place. In your case:
if [ "$i" -ne "$j" ]
then
# some code
else
# some code
fi
Since [ is a command, you might want to omit the if structure and use logical operators, taking advantage of lazy evaluation. The following means the same:
[ "$i" -ne "$j" ] && {
echo "hello" ;
echo "world" ;
} || {
echo "bye bye" ;
echo "world" ;
}

Related

Why is my zshrc function not working when adding arguments?

I am trying to make a function to start, stop or restart from any directory
The code works fine without any arguments but when adding any argument I get the webserver:6: = not found error, when testing the variables everything looks like it should work
function webserver {
#echo $USERNAME
'echo $1
if [ "$1" != "" ]
then
if [ "$1" == "start"]
then
/Users/$USERNAME/start.sh
fi
if [ "$1" == "stop"]
then
/Users/$USERNAME/stop.sh
fi
if [ "$1" == "restart"]
then
/Users/$USERNAME/restart.sh
fi
else
echo "Invalid arguments! Valid arguments are : start stop restart"
fi
}
Why is this code not working?
There's a single-quote before the echo $1 command, which'll cause different trouble. Is that a typo?
The mains problem is that your comparison syntax is wrong; in a [ ] test, use a single = for string equality test, and you need spaces between each syntactic element, including before the final ].
if [ "$1" == "start"] # Bad, will give errors
if [ "$1" = "start" ] # Good, will work as expected
Also, I'd replace that series of if statements with a either a case statement, or a single if ... elif ... elif, since only one branch will ever be taken.
case "$1" in
start)
/Users/$USERNAME/start.sh ;;
stop)
/Users/$USERNAME/stop.sh ;;
restart)
/Users/$USERNAME/restart.sh ;;
*) # This is the case equivalent of "else"
echo "Invalid arguments! Valid arguments are : start stop restart" ;;
esac
like Gordon said, the syntax for zsh is wrong with only one [ ].
according to "==" logical operator and zsh version 5.7.x (installed using Homebrew)
Simple answer: a == is a logical operator only inside [[ … ]] constructs.
And it works also in ksh and bash.
When used outside a [[ … ]] construct a =cmd becomes a filename expansion operator but only in zsh
$ echo ==
zsh: = not found

How to apply multiple validations to an argument in bash script?

I have a bash script that reads input from the user and validates if the inputted value exists (non-blank) and is an even integer. I'm using the terse test "$1" to test if input exists but combining it with other validation methods does not seem to work. My validation methods are like so:
readValidBookLength() {
BOOKLENGTH=$1
while ! [ isValidBookLength $BOOKLENGTH ] && ! [ isBookLengthNumeric $BOOKLENGTH ] && [isBookLengthEvenNumber $BOOKLENGTH]; do
echo -e 'Book length? (HINT: An even number!): \c'
read -r BOOKLENGTH
done
}
isValidBookLength() {
test "$1"
}
isBookLengthNumeric() {
echo "I GOT HERE!"
BOOKLENGTH=$1
echo "${BOOKLENGTH}"
reg='^[0-9]+$'
if ! [[ $BOOKLENGTH =~ $reg ]] ; then
return 1
else
return 0
fi
}
isBookLengthEvenNumber() {
echo "I GOT HERE 2!"
BOOKLENGTH=$1
echo "${BOOKLENGTH}"
if [ $((BOOKLENGTH%2)) -eq 0 ] ; then
return 0
else
return 1
fi
}
Is this pattern of seeking a valid input after multiple validations correct. What am I missing here?
You shouldn't put [ before the calls to your validation functions. [ is a short name for the test command. You also need to group all the tests together and negate the whole group:
while ! { isValidBookLength "$BOOKLENGTH" && isBookLengthNumeric $BOOKLENGTH && isBookLengthEvenNumber $BOOKLENGTH; }; do
It looks like you want the loop to continue to execute if any of the tests fail. That means you should use ||, not &&, to combine the tests.

Bash IF logic error

I'm just starting to learn bash scripting and to do a sort of hello world program I came up with this:
#!/bin/bash
clear
echo "This is a test script"
echo
echo
f="foo"
b="bar"
COUNTER=10
until [ $COUNTER -lt 0 ]; do
if [ $f="foo" ]; then
echo first
echo $f $b
f="bar"
b="food"
else if [ $f="bar" ]; then
echo second
echo $f $b
f="foo"
b="bar"
else
echo neither
fi
fi
let COUNTER-=1
done
Now the expected outcome is to clear the screen and say:
This is a test script
<space>
<space>
first
foo bar
second
bar food
first
foo bar
second
bar food
...
But instead the outcome is
This is a test script
<space>
<space>
first
foo bar
first
bar food
first
bar food
...
How is is getting passed the first if every time, when the value is "bar". I've tried with quotes, without quotes, double equals...I'm at a loss. can anyone shed some light?
You should add space between after and before brackets on your condition statements:
if [ "$f" = "foo" ]; then
else if [ "$f" = "bar" ]; then
It's also a good idea to place variables around double quotes to prevent word expansion.
In bash as well, it's recommended to use [[ ]] over [ ]:
if [[ "$f" = "foo" ]; then
else if [[ "$f" = "bar" ]]; then
Your loop can also be simplified with for loop:
for ((i = 10; i; --i)); do
...
done
Your extra fi is also probably not needed:
fi
fi
else if [ $f="bar" ]; then
] is actually a (built-in) command, not just part of the shell syntax. It takes one or more arguments, the last of which must be a ]. In order for the arguments to be recognized, they have to be separated by whitespace.
With a single argument (plus the closing ]), the [ command returns false if that argument is an empty string, true if it's non-empty. The argument is sees is $f="bar", which expands to foo=bar, which is non-empty and therefore true.
Adding spaces around the = should fix this:
else if [ $f = "bar" ]; then
You also need spaces after the [ command and before the closing ]; fortunately, you already do.

shell script if else loop not working

Given the following programme which reads in user input twice
function search_grep
{
if [ "$2" == "" ];then
for x in "${title[#]}"
do
value=$(echo $x | grep "$1")
if [ "$value" != "" ];then
echo "$value"
fi
done
elif [ "$1" == "" ];then
hello="123"
echo "$hello"
fi
}
echo -n "Enter title : "
read book_title
echo -n "Enter author : "
read author
title=(CatchMe HappyDay)
search_grep $book_title $author
it works as expected when i enter followed by HappyDay HOWEVER
When i enter foo followed by , I would expect console output to be
123
instead I am getting
Can someone explain to me , the programme is not executing the second elif loop though second input is
In both of your cases cases, the following:
search_grep $book_title $author
expands to a call with a single argument. Hence, the "then" clause is activated. The reason is that an unquoted argument consisting of whitespace expands to nothing and disappears. That is the way of bash.
If you want to pass search_grep two arguments, then you need to quote the variables:
search_grep "$book_title" "$author"
As shown here, you might try using = instead of ==
Or for an empty string comparison try -z

Meaning of "[: too many arguments" error from if [] (square brackets)

I couldn't find any one simple straightforward resource spelling out the meaning of and fix for the following BASH shell error, so I'm posting what I found after researching it.
The error:
-bash: [: too many arguments
Google-friendly version: bash open square bracket colon too many arguments.
Context: an if condition in single square brackets with a simple comparison operator like equals, greater than etc, for example:
VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
# some action
fi
If your $VARIABLE is a string containing spaces or other special characters, and single square brackets are used (which is a shortcut for the test command), then the string may be split out into multiple words. Each of these is treated as a separate argument.
So that one variable is split out into many arguments:
VARIABLE=$(/some/command);
# returns "hello world"
if [ $VARIABLE == 0 ]; then
# fails as if you wrote:
# if [ hello world == 0 ]
fi
The same will be true for any function call that puts down a string containing spaces or other special characters.
Easy fix
Wrap the variable output in double quotes, forcing it to stay as one string (therefore one argument). For example,
VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
# some action
fi
Simple as that. But skip to "Also beware..." below if you also can't guarantee your variable won't be an empty string, or a string that contains nothing but whitespace.
Or, an alternate fix is to use double square brackets (which is a shortcut for the new test command).
This exists only in bash (and apparently korn and zsh) however, and so may not be compatible with default shells called by /bin/sh etc.
This means on some systems, it might work from the console but not when called elsewhere, like from cron, depending on how everything is configured.
It would look like this:
VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
# some action
fi
If your command contains double square brackets like this and you get errors in logs but it works from the console, try swapping out the [[ for an alternative suggested here, or, ensure that whatever runs your script uses a shell that supports [[ aka new test.
Also beware of the [: unary operator expected error
If you're seeing the "too many arguments" error, chances are you're getting a string from a function with unpredictable output. If it's also possible to get an empty string (or all whitespace string), this would be treated as zero arguments even with the above "quick fix", and would fail with [: unary operator expected
It's the same 'gotcha' if you're used to other languages - you don't expect the contents of a variable to be effectively printed into the code like this before it is evaluated.
Here's an example that prevents both the [: too many arguments and the [: unary operator expected errors: replacing the output with a default value if it is empty (in this example, 0), with double quotes wrapped around the whole thing:
VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
# some action
fi
(here, the action will happen if $VARIABLE is 0, or empty. Naturally, you should change the 0 (the default value) to a different default value if different behaviour is wanted)
Final note: Since [ is a shortcut for test, all the above is also true for the error test: too many arguments (and also test: unary operator expected)
Just bumped into this post, by getting the same error, trying to test if two variables are both empty (or non-empty). That turns out to be a compound comparison - 7.3. Other Comparison Operators - Advanced Bash-Scripting Guide; and I thought I should note the following:
I used -e thinking it means "empty" at first; but that means "file exists" - use -z for testing empty variable (string)
String variables need to be quoted
For compound logical AND comparison, either:
use two tests and && them: [ ... ] && [ ... ]
or use the -a operator in a single test: [ ... -a ... ]
Here is a working command (searching through all txt files in a directory, and dumping those that grep finds contain both of two words):
find /usr/share/doc -name '*.txt' | while read file; do \
a1=$(grep -H "description" $file); \
a2=$(grep -H "changes" $file); \
[ ! -z "$a1" -a ! -z "$a2" ] && echo -e "$a1 \n $a2" ; \
done
Edit 12 Aug 2013: related problem note:
Note that when checking string equality with classic test (single square bracket [), you MUST have a space between the "is equal" operator, which in this case is a single "equals" = sign (although two equals' signs == seem to be accepted as equality operator too). Thus, this fails (silently):
$ if [ "1"=="" ] ; then echo A; else echo B; fi
A
$ if [ "1"="" ] ; then echo A; else echo B; fi
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi
A
... but add the space - and all looks good:
$ if [ "1" = "" ] ; then echo A; else echo B; fi
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi
B
Another scenario that you can get the [: too many arguments or [: a: binary operator expected errors is if you try to test for all arguments "$#"
if [ -z "$#" ]
then
echo "Argument required."
fi
It works correctly if you call foo.sh or foo.sh arg1. But if you pass multiple args like foo.sh arg1 arg2, you will get errors. This is because it's being expanded to [ -z arg1 arg2 ], which is not a valid syntax.
The correct way to check for existence of arguments is [ "$#" -eq 0 ]. ($# is the number of arguments).
I also faced same problem. #sdaau answer helped me in logical way. Here what I was doing which seems syntactically correct to me but getting too many arguments error.
Wrong Syntax:
if [ $Name != '' ] && [ $age != '' ] && [ $sex != '' ] && [ $birthyear != '' ] && [ $gender != '' ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "Enter all the values"
fi
in above if statement, if I pass the values of variable as mentioned below then also I was getting syntax error
export "Name"="John"
export "age"="31"
export "birthyear"="1990"
export "gender"="M"
With below syntax I am getting expected output.
Correct syntax:
if [ "$Name" != "" -a "$age" != "" -a "$sex" != "" -a "$birthyear" != "" -a "$gender" != "" ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "it failed"
fi
There are few points which we need to keep in mind
use "" instead of ''
use -a instead of &&
put space before and after operator sign like [ a = b], don't use as [ a=b ] in if condition
Hence above solution worked for me !!!
Some times If you touch the keyboard accidentally and removed a space.
if [ "$myvar" = "something"]; then
do something
fi
Will trigger this error message. Note the space before ']' is required.
I have had same problem with my scripts. But when I did some modifications it worked for me. I did like this :-
export k=$(date "+%k");
if [ $k -ge 16 ]
then exit 0;
else
echo "good job for nothing";
fi;
that way I resolved my problem. Hope that will help for you too.

Resources