compared two parameters using "<" in shell - linux

let's assign like this:
a=7
b=29
[[ $a < $b ]] && echo dasf
it doesn't work!!
however, when
a=1
with b and command same, it works well.
That's very funky! Can somebody explain that?

You're comparing the variables lexically, not numerically.
Try
[[ $a -lt $b ]] && echo smaller
or
(( $a < $b )) && echo smaller

Related

Check what kind of parameters shell script got

I need some help in my shell script. I have this:
#!/bin/bash
for i in $*
do
if [[ $i = *[a-zA-Z] ]]
then echo $i contains just letters.
elif [[ $i = *[a-zA-Z0-9] ]]
then echo $i contains numbers and letters.
else
echo Error.
done
I would like the result to be, for example:
$ ./script.sh abCd a9d a-b
abCd contains just letters.
a9d contains numbers and letters.
Error.
But I get contains just letters in every case.
I also tried grep command too, but without success.
Your RegEx are wrong. Try the following:
#!/bin/bash
for i in $*
do
if [[ $i =~ ^[a-zA-Z]+$ ]]
then echo $i contains just letters.
elif [[ $i =~ ^[a-zA-Z0-9]+$ ]]
then echo $i contains numbers and letters.
else
echo Error.
fi
done

Simple int condition in Bash doesn't make sense

x=23;
y=223;
if [[ $x < $y ]]
then
echo "TRUE"
else
echo "FALSE"
fi
So this always print FALSE even thought 23 is clearly less than 223. I am new to bash so I might be missing something obvious. I tried substituting $x and $y with their actually value and that means to work fine. Please send help
< performs lexicographic ordering of strings. To get numeric ordering, use -lt.
x=23;
y=223;
if [[ $x -lt $y ]]
then
echo "TRUE"
else
echo "FALSE"
fi
Or you can use an arithmetic expression instead of a conditional expression:
if (( $x < $y ))

How to find min of two variables in linux

i have two variables
$a and $b
is there shell script command to assign the value of minimum variable to $c
i.e
$c = min($a,$b)
and some command that can work across all platforms hp-ux,aix,linux_x_64
thanks in advance
EDIT:
default shell is ksh
and below the script im trying to run
rm abc.log
near_dr=`sqlplus -s tcs384160/tcs#1234 <<\EOF
set pagesize 0 feedback off verify off heading off echo off
select max(sequence#) from v$archived_log where applied='YES' and thread#=1 and
dest_id=2;
exit;
EOF`
DR=`sqlplus -s tcs384160/tcs#1234 <<\EOF
set pagesize 0 feedback off verify off heading off echo off
select max(sequence#) from v$archived_log where applied='YES' and thread#=1 and
dest_id=3;
exit;
EOF`
safe_var=$([ $near_dr -le $DR ] && echo "$near_dr" || echo "$DR")
echo $safe_var;
ulimit=`expr $safe_var - 30`;
llimit=`expr $ulimit - 1000`;
echo $llimit;
echo $ulimit;
i=$llimit
while [ $i -le $ulimit ];
do
ls evdprd_1_${i}_*.arc>>abc.log;
let i=i+1;
done;
recover -s ttlhydnwr -c tphtpsd2<<EOF >> abc.log
ls -1 *.arc
exit
EOF
sed -e 's/[\t ]//g;/^$/d' abc.log > abc1.log
awk '++seen[$0] == 2' abc1.log > actual.log
please ignore the sqlplus parts as those are working fine the only problem is the $safe_var needing the minimum of the two values
There is no function, but you can create it:
(( $a <= $b )) && echo "$a" || echo "$b"
The condition && action1 || action2 does evaluate the condition. If it is true, then perform action1; otherwise, perform action2.
To store the result into a variable, do:
min=$( (( $a <= $b )) && echo "$a" || echo "$b" )
Update
It seems that the $( (( )) ) syntax is giving problems. Hence, let's replace it to:
[ $a -le $b ] && echo "$a" || echo "$b"
or assigning value:
min=$([ $a -le $b ] && echo "$a" || echo "$b")
Sample
$ a=3
$ b=4
$ [ $a -le $b ] && echo "$a" || echo "$b"
3
$ b=1
$ [ $a -le $b ] && echo "$a" || echo "$b"
1
$ b=3
$ [ $a -le $b ] && echo "$a" || echo "$b"
3
You could do in this way too:
x=1
y=2
echo $(($x<$y?$x:$y))
1
To store value in other variable:
z=$(($x<$y?$x:$y)) #Min
z=$(($x<=$y?$x:$y)) #Min and equal
z=$(($x>$y?$x:$y)) #Greater
z=$(($x>=$y?$x:$y)) #Greater and equal
In ksh, this works fine
$ near_dr=5 DR=10
$ save_var=$(( near_dr < DR ? near_dr : DR )) ; echo $save_var
5
$ near_dr=15 DR=10
$ save_var=$(( near_dr < DR ? near_dr : DR )) ; echo $save_var
10
$ near_dr=15 DR=15
$ save_var=$(( near_dr < DR ? near_dr : DR )) ; echo $save_var
15
So you can write a function:
min() {
echo $(( $1 < $2 ? $1 : $2 ))
}
safe_var=$(min $near_dr $DR)
This is the same as #Liaraz's answer, except "Variables can be referenced by name within an arithmetic
expression without using the parameter expansion syntax." (ksh man page, section Arithmetic evaluation)
Ksh93 custom arithmetic function example:
function .sh.math.min a b {
.sh.value=$(( a<b ? a : b ))
}
$ echo $(( min(1,3) ))
1
$ echo $(( min(5,3) ))
3
if you are sure the value of variables are integers, use #fedorqui's answer. It's short and neat.
however, if you are not sure about that, they could be e.g. float numbers:
kent$ a=3.57
kent$ b=13.5
kent$ (($a < $b)) && echo "y" || echo "n"
bash: ((: 3.57 < 13.5: syntax error: invalid arithmetic operator (error token is ".57 < 13.5")
n
this would work for all cases:
kent$ awk -v a="$a" -v b="$b" 'BEGIN{print (a>b)?b:a}'
3.57

use of special characters in if statement in bash

I'm unfamiliar with bash scripting. I wrote a script check arguments. the code is:
for (( i=1; i<=4; i++ ))
do
if ! [[ "$"$i =~ .*[^0-9].* ]]; then
echo "bad input was $i"
fi
done
Actually i want to split non numerical arguments, But it seems that "$"$i is wrong because the answer is always true or false independent of arguments.
can anybody tell me what is the mistake?
You seem to be trying to use indirect parameter expansion.
for (( i=1; i<=4; i++ ))
do
if ! [[ ${!i} =~ .*[^0-9].* ]]; then
echo "bad input was $i"
fi
done
However, it's cleaner to just iterate over the parameters directly, rather than over their position:
for arg in "${#:1:4}"; do
if ! [[ $arg =~ .*[^0-9].* ]]; then
echo "bad input was $arg"
fi
done
If condition should be like this:
if [[ ! "$i" =~ [^0-9] ]]; then
OR remove 2 negatives:
if [[ "$i" =~ [0-9] ]]; then
OR use glob:
if [[ "$i" == *[0-9]* ]]; then
Which means $i contains a digit 0-9
Update: Based on your comments it looks like you are looking for BASH variable indirection like this script check-num.sh:
#!/bin/bash
for (( i=1; i<=$#; i++ )); do
[[ "${!i}" != *[0-9]* ]] && echo "bad input was ${!i}"
done
You can run this script as: ./check-num.sh 1 2 x 4 a
Note how ${!i} syntax is being used here to access the variable's $1, $2, $3 etc that is called BASH variable indirection. You shouldn't use $$i for this purpose.
As per BASH manual:
If the first character of parameter is an exclamation point, a level of variable indirection is introduced. Bash uses the value of the variable formed from
the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the
value of parameter itself.
Use something like this :
for i in "$#"; do
[[ $i =~ .*[^0-9].* ]] || echo "bad input was $i"
done
N.B : It's not necessary to use doubles quotes arround the variable with the [[ internal instruction.

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