if statement with and shell script - bash

I am trying to make a if statement where if the hour is between 13 and 23 it will set the hour back to 12. Now below is a snippet of my shell script code:
#!/bin/bash
HOUR=$1
if [ $HOUR > 13 ] && [ $HOUR < 23 ];
then
$HOUR=12
fi
Now I am getting errors when I run this script. How can I tweak this script to get the desired conditions specified above?

if [ $HOUR -gt 13 -a $HOUR -lt 23 ]
then
HOUR=12
fi
Use -gt and -lt instead of > < (redirection operations)
Use -a for AND in the same expression
Fix typo $HOURS=12 (removed $)

You need to evaluate that expression arithmetically rather than textually. Try something like this:
#!/bin/bash
HOUR=$1
if (( $HOUR > 13 )) && (( $HOUR < 23 ));
then
HOUR=12
fi

To use < or > in a Bash test, you need the [[...]] form of test construct. HOWEVER, that does not do what you think it does. Those are lexicographical tests.
You can either use -lt and -gt for arithmetic comparisons:
$ H=14
$ [[ $H -gt 13 && $H -lt 23 ]]; echo $?
0
(0 means True in this case...)
Or, use the ((...)) for arithmetic test construct. Then you can use a C style ternary assignment to test and assign in one step:
$ H=20
$ (( H = H>13 && H<23 ? 12 : H )); echo $H
12

Shorter version:
#!/bin/bash
HOUR=$1
[[ $HOUR > 13 && $HOUR < 23 ]] && HOUR=12

Related

How to say less than but no equal to in bash?

I'm getting an error with this, I did my research but found nothing.
if [ $value -lt 3 -ne 1 ]; then
execute code
fi
line 6: [: syntax error: -ne unexpected
One way to make this work is
if [ "${value}" -lt 3 ] && [ "${value}" -ne 1 ]; then
echo "Hello"
fi
I like to switch to arithmetic expressions using (( when I need tests like these:
declare -a values=(1 2 3)
for value in "${values[#]}"; do
if (( value != 1 && value < 3 )); then
echo "execute code for $value"
fi
done
The above outputs:
execute code for 2
use (( )) brackets for arithmetic operations and [[ ]] for strings comparison
$ is redundant in round brackets so (( $a == 1 )) is the same as (( a == 1 ))
typeset a=2
(( a < 3 )) && (( a != 1 )) && echo "Execute code"
more details : http://faculty.salina.k-state.edu/tim/unix_sg/bash/math.html

shell script - why code executing in infinite loop [duplicate]

I wrote a bash script that performs a curl call only during business hours. For some reason, the hourly comparison fails when I add an "-a" operator (and for some reason my bash does not recognize "&&").
Though the script is much larger, here is the relevant piece:
HOUR=`date +%k`
if [ $HOUR > 7 -a $HOUR < 17 ];
then
//do sync
fi
The script gives me the error:
./tracksync: (last line): Cannot open (line number): No such file
However, this comparison does not fail:
if [ $DAY != "SUNDAY" -a $HOUR > 7 ];
then
//do sync
fi
Is my syntax wrong or is this a problem with my bash?
You cannot use < and > in bash scripts as such. Use -lt and -gt for that:
if [ $HOUR -gt 7 -a $HOUR -lt 17 ]
< and > are used by the shell to perform redirection of stdin or stdout.
The comparison that you say is working is actually creating a file named 7 in the current directory.
As for &&, that also has a special meaning for the shell and is used for creating an "AND list" of commands.
The best documentation for all these: man bash (and man test for details on comparison operators)
There are a few answers here but none of them recommend actual numerical context.
Here is how to do it in bash:
if (( hour > 7 && hour < 17 )); then
...
fi
Note that "$" is not needed to expand variables in numerical context.
I suggest you use quotes around variable references and "standard" operators:
if [ "$HOUR" -gt 7 -a "$HOUR" -lt 17 ]; ...; fi
Try using [[ instead, because it is safer and has more features. Also use -gt and -lt for numeric comparison.
if [[ $HOUR -gt 7 && $HOUR -lt 17 ]]
then
# do something
fi

bash - test MM between 01 and 12

I have $MM. It can be:
01-12
But not 1-12 (i.e. every single digit will have a 0 in front, 1=01, 2=02 etc.)
I need to write a test that ensures that MM is valid, and fail if not. I have tried:
MM=09
if [[ "$MM" -le 0 ]] && [[ "$MM" -ge 13 ]]; then
echo "MM is not between 01 and 12"
fi
errors:
[[: 09: value too great for base (error token is "09")
I have also tried various combinations:
MM=13
if [ $MM -le 0 ] && [ $MM -ge 13 ]; then
echo "MM is not between 01 and 12"
fi
shows nothing when MM is 13 (to be expected)
MM=13
if [ $MM <= 0 ] && [ $MM => 13 ]; then
echo "MM is not between 01 and 12"
fi
errors
=: No such file or directory
I know I am doing something fundamentally wrong here, I'm just not sure what it is. I also need this logic to apply similar checks for:
DD needs to be between 01-31
hh needs to be between 00-23
mm needs to be between 00-59
thanks!
First of all leading 0 makes shell interpret it as octal number and 09 is invalid octal so you will get: 09: value too great for base error.
You can use use BASH regex for this validation:
mm='09'
[[ $mm =~ ^(0[1-9]|1[0-2])$ ]] && echo "valid" || echo "invalid"
valid
mm='9'
[[ $mm =~ ^(0[1-9]|1[0-2])$ ]] && echo "valid" || echo "invalid"
invalid
mm='13'
[[ $mm =~ ^(0[1-9]|1[0-2])$ ]] && echo "valid" || echo "invalid"
invalid
mm='12'
[[ $mm =~ ^(0[1-9]|1[0-2])$ ]] && echo "valid" || echo "invalid"
valid
Just use arithmetic comparison, specifying the radix:
if (( 10#$mm < 1 || 10#$mm > 12 )); then
echo "mm is not between 1 and 12"
fi
or, similarly,
if (( 10#$mm >= 1 && 10#$mm <= 12 )); then
echo "mm is between 1 and 12"
fi
You specify the radix by using radix# in front of the number/variable expansion. Here we need radix 10, hence the 10# in front of the expansion $mm. See Shell Arithmetic in the reference manual (near the end of the section).
The other answer (with regexes) is good, but doesn't carry the proper semantic, and can be really awkward with more complicated ranges.
In case you want sh compatibility, the case statement is handy.
case $MM in ? | ???* | *[!0-9]* | 1[3-9] | [2-9]? | 00) echo Invalid;; esac
This triggers on, in turn, too short, too long, non-numeric, too large smaller than 20, other too large numbers, and all zeros.

Using if and controlling numbers in ksh

I would like to download file with the format cars000.txt, cars003.txt,cars006.txt, till cars105.txt...interval of 3 as you can see
I use the following code in ksh, but after downloading cars012.txt, it fails, it begins to download cars13.txt,...and I don't wish it. What does it fails in the code?
FHR=000
while [ $FHR -le 105 ]
do
file=cars${FHR}.txt
wget http://${dir_target}/${file}
(( FHR = $FHR + 03 ))
echo $FHR
if [[ $FHR -le 10 ]]; then FHR="00"$FHR
else FHR="0"$FHR
fi
done
You should decide: is FHR a string, a decimal or an octal.
You are mixing them currently.
Try the next improvement:
FHR=0
while [ ${FHR} -le 105 ]; do
file=cars${FHR}.txt
(( FHR = FHR + 3 ))
echo Without leading zero: FHR=${FHR}
if [[ $FHR -le 10 ]]; then
echo "FHR=00${FHR}"
else
echo "FHR=0${FHR}"
fi
sleep 1
done
(The next improvement might be using printf or awk and no zero for 102/105)

Problem with logical operator in bash script

I read in tldp.com that
if [ $condition1 ] && [ $condition2 ]
Same as: if [ $condition1 -a $condition2 ]
Returns true if both condition1 and condition2 hold true..."
but when I tried
if [ $a == 2 ] || [ $b == 4 ]
then
echo "a or b is correct"
else
echo "a and b are not correct"
fi
it gives error. I'm using bash.
Your logic is ok but your comparison operators are incorrect, you should use the '-eq' for comparing integers and '==' for strings. See 'man test' for quick reference, though it's also documented in 'man bash'.
When using integer comparison it is always best to initialise variables to 0 as well otherwise if they remain unset you will get errors.
As mentioned by c00k, use [[ rather than [ if using bash as it is a builtin so bash will not need to shell out to use the /usr/bin/[ command.
i.e.
a=0;b=0
# do something else with a or b
if [[ $a -eq 2 ]] || [[ $b -eq 4 ]]
then
echo "a or b is correct"
else
echo "a and b are not correct"
fi
If you're using Bash, then drop the single [ and use double ones [[.
For arithmetic operations, use ((.
So you'd want to write this:
if (( a == 2 )) || (( b == 4 )); then
echo "foo"
fi # etc
Did you assign a value to a and b? If not you have to (otherwise you definitely should) quote your variables with double quotes:
if [ "$a" == "2" ] || [ "$b" == "4" ]; then
echo "a or b is correct";
else
echo "a and b are not correct";
fi
Correct me if I'm wrong. && and || are bash comparison
#!/usr/bin/ksh
set -x ###### debug mode on
while :
do
dt=`date '+%M'`
if ([ "$dt" -ge "15"] && [ "$dt" -le "17" ]) || ([ "$dt" -ge "25" ] && [ "$dt" -le "27" ])
then
echo "Time-->minutes between 15 to 17 OR 25 to 27"
else
echo "Time--> minutes out of range"
fi
sleep 300 ##### sleep for 5 minutes
done
------------- below lines are debug output
+ + date +%M
dt=17
+ [ 17 -ge 15 ]
+ [ 17 -le 17 ]
+ echo Time--> minutes between 15 to 17 OR 25 to 27
Time--> minutes between 15 to 17 OR 25 to 27
+ date
Sat Mar 3 15:17:23 AST 2012
+ sleep 300
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ :
+ + date +%M
dt=22
+ [ 22 -ge 15 ]
+ [ 22 -le 17 ]
+ [ 22 -ge 25 ]
+ echo Time--> minutes out of range
Time--> minutes out of range
+ sleep 300
^C$ ######## breaking out of loop(terminating the execution).
$
$ env |grep -i shell
+ grep -i shell
+ env
SHELL=/bin/ksh
$ set +x ##### ending debug mode.

Resources