How to compare number with string by -gt in shell programming - linux

I don't know if exist a var $b ,make the value of the expression :
[[ "$a" -gt "$b" ]] && [[ "$b" -gt 88888888 ]]
is true?...

It's not terribly well documented (IIRC), but -gt (and the other integer comparison operators) forces the comparison to be made in an arithmetic context, which means an empty value of $b is treated the same as 0.
$ [[ 3 -gt $undefined ]] && echo true
true
$ [[ -3 -lt $undefined ]] && echo true
true
$ [[ 0 -eq $undefined ]] && echo true
true
This is more clearly seen using the fact that strings are recursively expanded as variables until an integer is found as well:
$ foo=bar
$ bar=3
$ [[ 3 -eq bar ]] && echo true
true
$ [[ 3 == bar ]] || echo false
false

Related

Bash: Check if a string contain specific alphabets and comma

I am trying to parse and validate a string in Bash which is comma separated. The expected input is: X4,Y1,Z5
Conditions: The string should have only X,Y or Z alphabets, followed by any number. The string should not have any special characters other than comma. Please suggest.
X4,Y1,Z5 (This is OK)
Z2,y6,X1 (This is OK)
X3Y6,Z8 (This is not OK)
A1,B2,X8 (This is not OK)
N1P8* (This is not OK)
I have tried the following but this is not working as expected.
if [[ ! $str =~ ['!##$%^&*()_+'] ]] && [[ $str =~ [XYZxyz] ]]; then
echo "OK"
else
echo "Not OK"
fi
I suppose there are additional conditions of the problem that were implied but not emphasized, such as:
The numbers may have more then one digit.
Each of X,Y,Z letters should be used exactly once.
With that in mind, I think this code will do:
if [[ "$1" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+){2}$ ]] &&
[[ "$1" =~ .*[Xx].* ]] &&
[[ "$1" =~ .*[Yy].* ]] &&
[[ "$1" =~ .*[Zz].* ]]
then
echo OK
else
echo Not OK
fi
Test cases:
#!/usr/bin/env bash
check() {
[[ "$1" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+){2}$ ]] &&
[[ "$1" =~ .*[Xx].* ]] &&
[[ "$1" =~ .*[Yy].* ]] &&
[[ "$1" =~ .*[Zz].* ]]
}
test_check() {
# code - expected exit code
# value - string to test
while read code value; do
check "$value"
if [[ $? == $code ]]; then
echo -e "\e[1;32mPassed:\e[0m $value"
else
echo -e "\e[1;31mFailed:\e[0m $value"
fi
done
}
test_check <<EOF
0 x1,y2,z3
0 X1,Y2,Z3
1 x,y,z
1 1,2,3
1 1x,2y,3z
0 z1,x2,y3
1 a1,b2,c3
1 x1
1 x1,y2 z1
1 x1,x2
1 x1;y2;z3
1 x1,y2
1 x1,y2,y3
0 x100,Y500,z0
0 x011,y015,z0
1 x1,x2,y3,z4
1 x1,y1,z1 .
EOF
P.S.
If any of the X,Y,Z may appear in the string more than once or not appear at all, then [[ "$str" =~ ^[XxYyZz][0-9]+(,[XxYyZz][0-9]+)*$ ]] should work. I added here + for digits to appear one or more times after the letter, and quoted "$str" in case if there's a space in it (or, to be precise, any character from $IFS variable).

What does "-?" mean in bash script

I have this script I am looking at, learning scripting but I cannot figure out what this line means:
if [[ $1 = "-?" ]]
I understand the $1 is first argument, but the after the equals I cannot figure it out the -?.h
if [[ $1 = "-?" ]]
then
echo "Use is: 235.sh <username>"
exit 1
I think it would be checking to see if the first argument is a string equal to -?
You can check this by running:
# [[ "a" = "-?" ]] && echo true
# [[ "-a" = "-?" ]] && echo true
# [[ "a-?" = "-?" ]] && echo true
# [[ "-?" = "-?" ]] && echo true
true
I would guess that is comparing something to the string "-?".

IF statement multiple and or conditions

I am using if statement with multiple condition in bash.
How can I reduce the following line syntax. So that it looks good from design point of you.
if [ "$1" != "-l" ] && [ "$1" != "-a" ] && [ "$1" != "-h" ] && [ "$1" != "" ] && [ "$1" = "-d" ] || [ "$1" = "-mv" ] || [ "$1" = "-dv" ] || [ "$1" = "-mr" ] || [ "$1" = "-dr" ];
Thanks
Use pattern matching.
if [[ $1 && $1 != -[lah] && $1 == -#(d|mv|dv|mr|dr) ]]; then
#(...) is an example of an extended pattern, which should be recognized by default inside [[ ... ]] in recent versions of bash. If you version is not so recent, add shopt -s extglob to the beginning of your script.
In fact, you can drop the $1 && $1 != -[lah] because its truth would be implied by the truth of $1 == -#(...).
if [[ $1 == -#(d|mv|dv|mr|dr) ]]; then
You could also just use a POSIX-compliant case statement:
case $1 of
-d|-mv|-dv|-mr|-dr) echo good option ;;
*) echo bad option ;;
esac
You can create 2 arrays for matching and non matching values and check if element $1 matches any element in the array or not like below.
nonmatch_array=( "-l" "-a" "-h" "" )
match_array=( "-d" "-mv" "-dv" "-mr" "-dr" )
if [ `echo ${match_array[#]} | grep "$1"` ] || ! [ `echo ${nonmatch_array[#]} | grep "$1"` ] ; then
echo "is in array"
else
echo "is not in array"
fi
Hope it should work for you.
First try to limit the length of the code on 1 line.
if [ [ "$1" != "-l" ]
&& [ "$1" != "-a" ]
&& [ "$1" != "-h" ]
&& [ -n "$1" ]
&& ( [ "$1" = "-d" ]
|| [ "$1" = "-mv" ]
|| [ "$1" = "-dv" ]
|| [ "$1" = "-mr" ]
|| [ "$1" = "-dr" ] ) ];
I added braces, to make clear what you mean with the or's.
Now you can combine all matches with a regular expression:
if [[ ! ("$a" =~ ^-(l|a|h|d|)$)
&& "$a" =~ ^-(mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
but reconsider what you are testing. The test will only be true when it matches -mv/-dv/-mr/-dr, so you do not need to test for the options lah.
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
You can use a variable for extracting the options:
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
Everytime the code is becoming hard to read (and also for long code or repeating statements), you should consider using a function.
The next function is short, but hard to read:
options="d|mv|dv|mr|dr"
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
checkoption1 "$a" &&
echo "Yes $a matches"
I would choose for a slightly more verbose function. I will include your original tests for lah for showing the possibilities.
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
checkoption2 "$a" &&
echo "Yes $a matches"
You should make some testruns before accepting your code.
I have made some tests with a small loop (now all answers together)
function checkoption1 {
[[ "$a" =~ ^-(${options})$ ]]
}
# checkoption return 0 for match,
# returns 1 for forbidden option
# returns 2 for undefined option
function checkoption2 {
case "$1" in
-d|-mv|-dv|-mr|-dr) return 0 ;;
-l|-a|-h|"") return 1;;
*) return 2;;
esac
}
for a in -mv mv -mvx -ms -mr -dr; do
if [[ ! ("$a" =~ ^-(l|a|h|)$)
&& "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
echo "Yes $a matches"
fi
options="d|mv|dv|mr|dr"
if [[ "$a" =~ ^-(${options})$ ]]; then
echo "Yes $a matches"
fi
checkoption1 "$a" &&
echo "Yes $a matches"
checkoption2 "$a" &&
echo "Yes $a matches 2"
done

When/how to use "==" or "-eq" operator in test?

In the following code I want to compare the command line arguments with the parameters but I am not sure what is the current syntax to compare the arguments with parameters..i.e "==" or "-eq".
#!/bin/bash
argLength=$#
#echo "arg = $1"
if [ argLength==0 ]; then
#Running for the very first
#Get the connected device ids and save it in an array
N=0
CONNECTED_DEVICES=$(adb devices | grep -o '\b[A-Za-z0-9]\{8,\}\b'|sed -n '2,$p')
NO_OF_DEVICES=$(echo "$CONNECTED_DEVICES" | wc -l)
for CONNECTED_DEVICE in $CONNECTED_DEVICES ; do
DEVICE_IDS[$N]="$CONNECTED_DEVICE"
echo "DEVICE_IDS[$N]= $CONNECTED_DEVICE"
let "N= $N + 1"
done
for SEND_DEVICE_ID in ${DEVICE_IDS[#]} ; do
callCloneBuildInstall $SEND_DEVICE_ID
done
elif [ "$1" -eq -b ]; then
if [ $5 -eq pass ]; then
DEVICE_ID=$3
./MonkeyTests.sh -d $DEVICE_ID
else
sleep 1h
callCloneBuildInstall $SEND_DEVICE_ID
fi
elif [ "$1" -eq -m ]; then
echo "Check for CloneBuildInstall"
if [ "$5" -eq pass ]; then
DEVICE_ID=$3
callCloneBuildInstall $SEND_DEVICE_ID
else
echo "call CloneBuildInstall"
# Zip log file and save it with deviceId
callCloneBuildInstall $SEND_DEVICE_ID
fi
fi
function callCloneBuildInstall {
./CloneBuildInstall.sh -d $SEND_DEVICE_ID
}
From help test:
[...]
STRING1 = STRING2
True if the strings are equal.
[...]
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.
But in any case, each part of the condition is a separate argument to [.
if [ "$arg" -eq 0 ]; then
if [ "$arg" = 0 ]; then
Why not use something like
if [ "$#" -ne 0 ]; then # number of args should not be zero
echo "USAGE: "
fi
When/how to use “==” or “-eq” operator in test?
To put it simply use == when doing lexical comparisons a.k.a string comparisons but use -eq when having numerical comparisons.
Other forms of -eq (equal) are -ne (not equal), -gt (greater than), -ge (greater than or equal), -lt (lesser than), and -le (lesser than or equal).
Some may also suggest preferring (( )).
Examples:
[[ $string == "something else" ]]
[[ $string != "something else" ]] # (negated)
[[ $num -eq 1 ]]
[[ $num -ge 2 ]]
(( $num == 1 ))
(( $num >= 1 ))
And always use [[ ]] over [ ] when you're in Bash since the former skips unnecessary expansions not related to conditional expressions like word splitting and pathname expansion.

ksh + compare numbers – two ways

the following example shows hot to compare numbers
I give here two different ways
one way with the ">" and "<"
and second way with "-gt" or "-lt"
both ways are work exactly
so what the differences between them ? or maybe there are not difference ?
example 1
ksh
a=1
b=2
[[ $a > $b ]] && echo ok
[[ $a < $b ]] && echo ok
ok
example 2
ksh
a=1
b=2
[[ $a -gt $b ]] && echo ok
[[ $a -lt $b ]] && echo ok
ok
In your examples there are no difference, but that is just an unfortunate choice of values for a and b.
-lt, -gt are for numeric comparison
< and > are for alphabetic comparison
$ a=12
$ b=6
$ [[ $a -lt $b ]] && echo ok
$ [[ $a &lt $b ]] && echo ok
ok

Resources