I have a sample logic. By calculation, it is -2 > 0 . This is a false condition and I get no result, but I am getting the value as abcd.
#!/bin/bash
Val1=1
Val2=1
Val3=2
Name=abcd
log=/tmp/log
if [ "$((Val1-(Val2 + Val3))) -ge 0" ] ; then echo "$Name" | tee -a "$log"; fi
I have verified on ShellCheck, and it is giving me this message. I couldn't get how to fix this?
$ shellcheck myscript
Line 7:
if [ "$((Val1-(Val2 + Val3))) -ge 0" ] ; then echo "$Name" | tee -a "$log"; fi
^-- SC2157: Argument to implicit -n is always true due to literal strings.
If you use [ 'a string' ], that's the same as [ -n 'a string' ]: it checks if the parameter is non-empty. You're providing the argument "$((Val1-(Val2 + Va3))) -ge 0", which evaluates to the string "-2 -ge 0". "Implicit -n" means that the shell really checks
if [ -n "-2 -ge 0" ]
and that is always true, because that's not an empty string.
The reason is your quoting. This would work instead:
if [ "$((Val1-(Val2 + Val3)))" -ge 0 ]
Strictly speaking, the quotes aren't necessary, but they don't hurt, either.
Or, since you're using Bash, you could use an arithmetic conditional:
if ((Val1 - (Val2 + Val3) > 0))
I figured after posting the question
#!/bin/bash
Val1=1
Val2=1
Val3=2
Name=abcd
log=/tmp/log
if [ "$((Val1-(Val2 + Val3)))" -ge 0 ] ; then echo "$Name" | tee -a "$log"; fi
Related
Usually i only use [[ for all kinds of test cases, because it's the most advanced way and it's more safe to use (Regex, ...).
I know that [[ executes different code than [, but according to the manpage and various documentations, it should at least handle options like "-n" the same way, but it doesn't.
-n STRING the length of STRING is nonzero
VAR=
if [[ -n $VAR ]]
then
echo "\$VAR is nonzero"
else
echo "\$VAR is zero"
fi
$VAR is zero
VAR=
if [ -n $VAR ]
then
echo "\$VAR is nonzero"
else
echo "\$VAR is zero"
fi
$VAR is nonzero
How is this even possible?
bash 4.1.2(1)
I think that your problem is related to quotes.
When you use [ -n $VAR ] the command that is executed won't contain any argument where $VAR should be:
$ set -x
$ [ -n $VAR ]
+ '[' -n ']'
This means that you are essentially testing whether the string -n is non-empty, because the following two tests are equivalent:
[ string ] # is a shorthand for
[ -n string ] # which is always true!
If you use quotes, then you get different behaviour:
$ [ -n "$VAR" ]
+ '[' -n '' ']'
Now you are testing whether the variable is non-empty, so you get the expected behaviour.
Quoting. You have to quote variables that you use in [:
$ VAR=
$ [ -n $VAR ]
$ echo $?
0
$ [ -n "$VAR" ]
$ echo $?
1
I found the following command:
var=""; [ -n $var ] && echo T || echo F
This command returns F.
In my understanding, $var is null so the command should return T.
I also checked this:
[ -n "" ] && echo T || echo F
This returns T as I expected.
I can not understand why
[ -n "" ] && echo T || echo F
returns T but
var="" [ -n $var ] && echo T || echo F
returns F?
I checked them on CentOS6.4 bash4.1.2
Executive summary: always quote your parameter expansions unless you know why it should not be. Use [ -n "$var" ] instead.
When unquoted,
[ -n $var ]
expands to
[ -n ]
that is, the empty string is removed from the input and bash is left with a one-argument call to [, which means the command returns true if the argument is non-empty. -n here is not an operator; it is simply a non-empty string.
You need to quote the parameter expansion so that
[ -n "$var" ]
expands to
[ -n "" ]
which is a two-argument call to [, which will do as you expect: test if the second argument has non-zero length.
This difference in output in case when you use a variable is that you don't quote the variable.
When you say:
[ -n $var ] && echo T || echo F
the shell reads it as:
'[' -n ']'
and returns T. This case is equivalent to saying [ foo ] which would always be true.
On the other hand, when you say:
[ -n "" ] && echo T || echo F
the shell would read it as:
'[' -n '' ']'
and return F.
The Bash Reference Manual says that
[ string ]
and
[ -n string ]
will both return true if the string 's length is not 0
but the fact is not as so
greet=
if [ $greet ]; then
echo '1'
else
echo '2'
fi
if [ -n $greet ]; then
echo '1'
else
echo '2'
fi
the output is
2
1
the Bash Reference Manual just says
-n string
string
True if the length of string is non-zero.
so, what the real difference between the two form?
As #user1502952 said, you need to use double-quotes; but let me explain why. Suppose you execute:
greet=
[ -n $greet ] && echo "it's nonblank"
When the shell parses the [ -n $greet ] part, it expands $greet to the empty string, and then does word splitting. For instance, if $greet expanded to something with spaces in the middle, it would treat each "word" as a separate argument to the [ command. In this case, however, $greet expands to nothing, which contains no "word"s at all, and hence is treated as zero arguments to [ -- it effectively vanishes from the command. So [ -n $greet ] is equivalent to [ -n ], which checks to see if the string "-n" is nonblank. It is, so it evaluates to true.
Compare this with [ -n "$greet" ]: in this case, the double-quotes allow the expansion of $greet, but prevent word splitting. So the [ command actually gets a zero-length second argument, realizes that -n is supposed to be an operator, and gets the expected answer.
when you are using -n option, it is required to use double quotes.
if [ -n "$greet" ]
as the string is empty the above expression evaluates to false, as the length is zero.
if [ "$greet" ]
this also evaluates to false as the string is empty.
Moreover to check for empty string, -z option can be used.
if [ -z "$greet" ]
this will be true as the string is empty.
Check this link too: http://tldp.org/LDP/abs/html/comparison-ops.html
Bash performs word splitting inside [ but not inside [[, so you don't have to quote parameters if you use [[:
$ x=
$ [ -n $x ]; echo $?; [ -n "$x" ]; echo $?
0
1
$ [[ -n $x ]]; echo $?; [[ -n "$x" ]]; echo $?
1
1
type shows [[ $x ]] as [[ -n $x ]]:
$ f() { [[ $x ]]; }; type f
f is a function
f ()
{
[[ -n $x ]]
}
function wtf() {
echo "\$*='$*'"
echo "\$#='$#'"
echo "\$#='"$#"'"
echo "\$#='""$#""'"
if [ -n "$*" ]; then echo " [ -n \$* ]"; else echo "![ -n \$* ]"; fi
if [ -z "$*" ]; then echo " [ -z \$* ]"; else echo "![ -z \$* ]"; fi
if [ -n "$#" ]; then echo " [ -n \$# ]"; else echo "![ -n \$# ]"; fi
if [ -z "$#" ]; then echo " [ -z \$# ]"; else echo "![ -z \$# ]"; fi
}
wtf
produces
$*=''
$#=''
$#=''
$#=''
![ -n $* ]
[ -z $* ]
[ -n $# ]
[ -z $# ]
though it seems to me that [-n $#] should be false because 7.3 Other Comparison Operators indicates that [ -n "$X" ] should be the inverse of [ -z "$X" ] for all $X.
-z
string is null, that is, has zero length
String='' # Zero-length ("null") string variable.
if [ -z "$String" ]
then
echo "\$String is null."
else
echo "\$String is NOT null."
fi # $String is null.
-n
string is not null.
The -n test requires that the string be quoted within the test brackets. Using an unquoted string with ! -z, or even just the unquoted string alone within test brackets (see Example 7-6) normally works, however, this is an unsafe practice. Always quote a tested string. [1]
I know $# is special but I did not know it was special enough to violate boolean negation. What is happening here?
$ bash -version | head -1
GNU bash, version 4.2.42(2)-release (i386-apple-darwin12.2.0)
The actual numeric exit codes are all 1 or 0 as per
$ [ -n "$#" ]; echo "$?"
0
When $# is empty, "$#" doesn't expand to an empty string; it is removed altogether. So your test is not
[ -n "" ]
but rather
[ -n ]
Now -n isn't an operator, but just a non-empty string, which always tests as true.
"$#" doesn't do what you expect. It's not a different form of "$*", it expands to the quoted list of arguments passed to the current script.
If there are no arguments, it expands to nothing. If there are two arguments a and b c, then it expands to "a" "b c" (i.e. it preserves whitespace in arguments) while "$*" expands to "a b c" and $* would expand to a b c (three words).
I'm receiveing an error on a simple script when using if/else statement.
The code:
#!/bin/sh
count=100
if [$count > 3]; then
echo "Test IF"
fi
The error: /bin/ash: line 6: [100: not found
#!/bin/sh
count=100;
if [ "$count" -gt 3 ]; then
echo "Test IF";
fi
Correct your syntax: spaces must be used around [ and ], parameter expansions must be quoted, and -gt is appropriate for numeric comparisons inside of [ ]. > in sh is used as redirection operator; if you want to use it in arithmetical comparison, you must use the bash-only syntax
$(( $count > 3 ))
#!/bin/sh
if [ $var -eq 12 ]; then
echo "This is a numeric comparison if example"
fi
if [ "$var" = "12" ]; then
echo "This is a string if comparison example"
fi
if [[ "$var" = *12* ]]; then
echo "This is a string regular expression if comparison example"
fi
The if statement in shell uses the command [.
Since [ is a command (you could also use 'test'), it requires a space before writing the condition to test.
To see the list of conditions, type:
man test
You'll see in the man page that:
s1 > s2 tests if string s1 is after string s2
n1 gt n2 tests if integer n1 is greater than n2
In your case, using > would work, because string 100 comes after string 3, but it is more logical to write
if [ $count -gt 3 ]; then
echo "test if"
fi
this will also do!
#!/bin/sh
count=100
if [ $count -gt 3 ];
then
echo "Test IF"
fi
if [[ "$x" == "true" ]]; then
echo "value matched"
else
echo "value doesn't matched"
fi