I found an interesting Bash script that will test if a variable is numeric/integer. I like it, but I do not understand why the "0" is not recognized as a number? I can not ask the author, hi/shi is an anonymous.
#!/bin/bash
n="$1"
echo "Test numeric '$n' "
if ((n)) 2>/dev/null; then
n=$((n))
echo "Yes: $n"
else
echo "No: $n"
fi
Thank you!
UPDATE - Apr 27, 2012.
This is my final code (short version):
#!/bin/bash
ANSWER=0
DEFAULT=5
INDEX=86
read -p 'Not choosing / Wrong typing is equivalent to default (#5): ' ANSWER;
shopt -s extglob
if [[ $ANSWER == ?(-)+([0-9]) ]]
then ANSWER=$((ANSWER));
else ANSWER=$DEFAULT;
fi
if [ $ANSWER -lt 1 ] || [ $ANSWER -gt $INDEX ]
then ANSWER=$DEFAULT;
fi
It doesn't test if it is a numeric/integer. It tests if n evaluates to true or false, if 0 it is false, else (numeric or other character string) it is true.
use pattern matching to test:
if [[ $n == *[^0-9]* ]]; then echo "not numeric"; else echo numeric; fi
That won't match a negative integer though, and it will falsely match an empty string as numeric. For a more precise pattern, enable the shell's extended globbing:
shopt -s extglob
if [[ $n == ?(-)+([0-9]) ]]; then echo numeric; else echo "not numeric"; fi
And to match a fractional number
[[ $n == #(?(-)+([0-9])?(.*(0-9))|?(-)*([0-9]).+([0-9])) ]]
Related
$var=1545334345
The $var is dynamic. How do I check if it starts with 15? I tried:
if [[ $var == 15* ]]; then
echo "Yes"
fi
and
if (( $var -eq 15* )); then
echo "Yes"
fi
Neither works.
Remove the $ from the assignment.
var=1545334345
The first if statement you wrote is correct.
if [[ $var == 15* ]]; then
echo "Yes"
fi
my if condition with gt compare value and also if the value is null, but I want that gt compare null value, I just want that he compare only value
res=''
toto=5
if [[ "$toto" -gt "$res" ]]; then
...
else
...
fi
fi
solution is that, but not very good
if [[ ! -z "$res" ]]; then
if [[ "$toto" -gt "$res" ]]; then
...
else
...
fi
fi
Use &&.
if [[ ! -z "$res" && "$toto" -gt "$res" ]]
Other improvements you could make:
Replace ! -z with -n.
Remove unnecessary quotes.
Use ((...)) for numerical comparisons.
if [[ -n $res ]] && ((toto > res))
This Shellcheck-clean code handles empty $res in another way:
#! /bin/bash
res=''
toto=5
if [[ -z $res ]] ; then
: # $res is empty so don't compare with $toto
elif (( toto > res )); then
echo 'toto is greater than res'
else
echo 'toto is less than or equal to res'
fi
However, it's debatable whether it's better or worse than the "not very good" option suggested in the question. Deeper nesting is usually worse, but if-the-else chains are best avoided. The only advantage I would claim for the code in this answer is that it has a convenient place to put a helpful comment if one is useful.
I am writing a bash script that sometimes will use environment variables GIT_DIR and GIT_WORK_TREE. The bash script can only operate correctly if either both variables exist or neither exist. In case there's a technical difference, it makes no difference
This works, but there has to be a better way:
if [[ -z "${GIT_DIR}" ]]; then
_GIT_DIR_EXISTS=0
else
_GIT_DIR_EXISTS=1
fi
if [[ -z "${GIT_WORK_TREE}" ]]; then
_GIT_WORK_TREE_EXISTS=0
else
_GIT_WORK_TREE_EXISTS=1
fi
if [[ "${_GIT_DIR_EXISTS}" -ne "${_GIT_WORK_TREE_EXISTS}" ]]; then
echo "GIT_DIR is ${GIT_DIR}"
echo "GIT_WORK_TREE is ${GIT_WORK_TREE}"
echo "Both or none must exist"
exit 1
fi
I tried:
if [[ (-z "${GIT_DIR}") -ne (-z "${GIT_WORK_TREE}") ]]; then
But that gives this error:
bash: syntax error in conditional expression
bash: syntax error near '-ne'
I then resorted to trying semi-random things, with varying errors:
if [[ -z "${GIT_DIR}" -ne -z "${GIT_WORK_TREE}" ]]; then
if [[ [-z "${GIT_DIR}"] -ne [-z "${GIT_WORK_TREE}"] ]]; then
if [[ [[-z "${GIT_DIR}"]] -ne [[-z "${GIT_WORK_TREE}"]] ]]; then
if [[ -z "${GIT_DIR}" ]] ^ [[ -z "${GIT_WORK_TREE}" ]]; then
if { [[ -z "${GIT_DIR}" ]] } -ne { [[ -z "${GIT_WORK_TREE}" ]] }; then
if [[ (( -z "${GIT_DIR}" )) -ne (( -z "${GIT_WORK_TREE}" )) ]]; then
I tried:
if [[ $(test -z "${GIT_DIR}") -ne $(test -z "${GIT_WORK_TREE}") ]]; then
But realized that doesn't work because it's a sub-process, and they'd need to be exported. as Socowl comments, this compares the outputs of the test commands which output nothing, not their exit statuses.
I apologize if this is a duplicate. I've searched here and google for a while, and must not be using the right terminology.
How about this:
if [[ "${GIT_DIR:+set}" != "${GIT_WORK_TREE:+set}" ]]; then
echo "GIT_DIR is '${GIT_DIR}'"
echo "GIT_WORK_TREE is '${GIT_WORK_TREE}'"
echo "Both or none must exist"
exit 1
fi
Explanation: ${var:+value} is a variant of parameter expansion that gives "value" if var is set to a nonempty string, or the empty string if var is unset or empty. So if both vars are unset/empty, it becomes if [[ "" != "" ]]; then, and if they're both set it becomes if [[ "set" != "set" ]]; then etc.
BTW, if you want to test whether the variables are set at all (even if to the empty string), use ${var+value} (note the lack of colon). The bash manual lists the :+ version, but not the + version.
COUNTER=0
let COUNTER=COUNTER+1
count=`ssh -i /var/www/.ssh/id_rsa_root -o stricthostkeychecking=no $host $cmd`
count1=`echo $count | awk '{print $4}'`
printf "count1 : $count1\n"
result1=${count1/.*}
if [ "$result1" -ge "0" ]; then
echo $host
else
echo $host
exit
fi
If the value of $result1 is INTEGER and greater than zero, it'll goto IF loop (works fine for me)
But when it is not INTEGER, it is coming to else loop (which it is suppose to do) with the following error in the Output
line 55: [: : integer expression expected
but i dont want the above error in my output. I tried to use 2>/dev/null with this but no luck.
please help!
If you want to handle an empty result gracefully, check for it explicitly:
if [ -z "$result1" ]; then
: "ignoring empty string"
elif [ "$result1" -ge 0 ]; then
printf '%s\n' "$host"
else
printf '%s\n' "$host"
exit
fi
You could also check if result1 is a valid integer before making arithmetic comparisons:
function isNumber () {
[[ $1 =~ ^-?[0-9]+$ ]]
}
if ! isNumber "$result1"; then
echo "not a number"
elif [ "$result1" -ge "0" ]; then
echo "null or positive"
else
echo "negative"
fi
Change if [ "$result1" -ge "0" ]; then to
if (( result1 >= 0 )); then
This syntax won't throw any errors if result1 isn't defined (or empty) or happen to be a string somehow.
I try to test if a string starts with a certain prefix. But my script seems not work (I would expect the "if" branch will not get run). Can some Bash expert help to take a look? thanks!
Here is my code and test result:
$ cat testb.bash
#!/bin/bash
my_var="abcdefg";
if [[ "${my_var:0:5}"=="order" ]]; then
echo "value of my_var is ${my_var}.";
fi;
if [[ "${my_var:0:5}" -eq "order" ]]; then
echo "value of my_var is ${my_var}.";
fi;
if [ "${my_var:0:5}"="order" ]; then
echo "value of my_var is ${my_var}.";
fi;
$ bash -x testb.bash
+ my_var=abcdefg
+ [[ -n abcde==order ]]
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
+ [[ abcde -eq order ]]
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
+ '[' abcde=order ']'
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
$
Whitespace is significant in this case. As you can see in the -x output, it understands the first condition as
[[ -n "${my_var:0:5}==order" ]]
Moreover, to test for a prefix, you can use a pattern:
[[ $my_var == order* ]]
To test the existence of substring, you can use either of these:
if [[ "$j" =~ string1 ]]; then
if [[ $j == *string1* ]]; then
In your particular case, you miss a space surounding ==, so instead of
if [[ "${my_var:0:5}"=="order" ]]; then
it should be
if [[ "${my_var:0:5}" == "order" ]]; then
^ ^
Finally, note that your condition was evaluated as true because it was evaluating if [ "string" ], which is true if string is not empty:
$ [ "a" ] && echo "yes"
yes
Test
$ cat a
#!/bin/bash
my_var="abcdefg";
if [[ "${my_var:0:5}" == "order" ]]; then
echo "value of my_var is ${my_var}."
elif [[ "${my_var:0:5}" == "abcde" ]]; then
echo "yeahaa"
else
echo "is not"
fi
$ ./a
yeahaa
Ok, i tested your code, you shoud such as the following code:
prefix="pre_order";
pre="pre_"
len=${#pre}
echo $len
if [[ "${prefix:0:len}" == "blahvlah" ]] ; then
echo "dddd"
fi;
Notes:
use == for string comparation
for ${} you should initilize a string variable before ${}
use len=${#pre} for lenght of string.
A POSIX-compliant way to test for a prefix is to attempt to remove the prefix, and compare the result to the original string. If the two are the same, the prefix is not present, the removal fails, and the expression expands to the original string.
prefix=foo
string=foobar
if [ "${string#$prefix}" = "$string" ]; then
printf "$string does not start with $prefix\n"
else
printf "$string starts with $prefix\n"
fi