I have issues with the last if in this example:
#!/bin/bash
sunrise="05:00:00";
currenttime=$(date -u +%H:%M:%S);
sunset="18:00:00"
if [[ "$sunrise" < "$currenttime" ]] ; then
echo works1;
fi
if [[ "$sunset" > "$currenttime" ]] ; then
echo works2;
fi
# during the day:
if [[ "$sunrise" < "$currenttime" ]] && [[ "$currenttime" > "$sunset" ]] ; then
echo works3;
fi
I get the output of the first two echo but not from the last one.
What am I doing wrong?
Of course I'm doing this tests now at 11:30.
If current time is 11:30, then 11:30 is smaller than 18:00 so the last condition of script is false.
Just to make this answer a bit more useful, you can use set -x to print all the steps that the script does which helps to find this kind of bugs.
And also, use "seconds from epoch" when working with time and transform them back at the end of the script: working with integer is much easier and safer than working with strings.
I suspect you want this:
if [[ "$currenttime" <= "$sunrise" ]] ; then
echo "before sunrise"
fi
if [[ "$currenttime" >= "$sunset" ]] ; then
echo "after sunset"
fi
if [[ "$sunrise" < "$currenttime" && "$currenttime" < "$sunset" ]] ; then
echo "daytime"
fi
Related
I am currently checking a .sh script just to do some basic things.
chmod +x catbash.sh
echo 'Hello, Please Enter your User Name'
echo
read VarUserName
currenttime=$(date +%H:%M)
if [[ $currenttime > 11:59 ]] || [[ $currenttime < 12:00 ]];
then echo 'Good Morning' $VarUserName'.'
fi
if [[ $currenttime > 12:00 ]] || [[ $currenttime < 16:59 ]];
then echo 'Good Afternoon' $VarUserName'.'
fi
if [[ $currenttime > 17:00 ]] || [[ $currenttime < 19:59 ]];
then echo 'Good Evening' $VarUserName'.'
fi
if [[ $currenttime > 20:00 ]] || [[ $currenttime < 23:59 ]];
then echo 'Good Night' $VarUserName'.'
fi
My issue is that i am trying to use the systems current time to be used in a if statement and depending on the time for a different output.
right now the script outputs all all of the "good...." echos and does not output a single echo depending on the time.
thank you for the help.
The problem is with your conditions, all of them permit any given value, did you maybe want to use && instead of ||?
It would be much simpler if you would write it using the elif construction and start from the later times and work your way down.
chmod +x catbash.sh
currenttime=$(date +%H:%M)
if [[ "$currenttime" > "19:59" ]]; then echo "Good Night ${USER}"
elif [[ "$currenttime" > "16:59" ]]; then echo "Good Evening ${USER}"
elif [[ "$currenttime" > "11:59" ]]; then echo "Good Afternoon ${USER}"
elif [[ "$currenttime" > "05:59" ]]; then echo "Good Morning ${USER}"
else echo "Good Night ${USER}"
How can this while loop be limited to maximum 10 retries?
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
sleep 1
done
Keep a counter:
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && break
sleep 1
done
You can also use a for loop and exit it on success:
for try in {1..10} ; do
[[ -d /somemount/share/folder ]] && break
done
The problem (which exists in the other solutions, too) is that once the loop ends, you don't know how it ended - was the directory found, or was the counter exhausted?
I would comment but I do not have enough points for that. I want to contribute anyway.
So this makes it work even if the while loop is nested in another loop. before the break the c variable is being reset to zero.
credits to #anubhava who came up with the original solution.
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && c=0 && break
sleep 1
done
You can use until (instead of "while ! ... break), with a counter limit:
COUNT=0
ATTEMPTS=10
until [[ -d /somemount/share/folder ]] || [[ $COUNT -eq $ATTEMPTS ]]; do
echo -e "$(( COUNT++ ))... \c"
sleep 1
done
[[ $COUNT -eq $ATTEMPTS ]] && echo "Could not access mount" && (exit 1)
Notes:
Just like setting counter as variable, you can set var condition="[[ .. ]]", and use until eval $condition to make it more generic.
echo $(( COUNT++ )) increases the counter while printing.
If running inside a function, use "return 1" instead of "exit 1".
I have a main script that calls doSomeWork.sh each and every 10 mins.
But the condition is that the doSomeWork.sh should not run between 23:30:00 to 03:00:00.
I have made my script to look something like the below.
#!/bin/ksh
prodStartTime="030000"
prodEndTime="233000"
currentTime=`date +"%H%M%S"`
echo $prodStartTime
echo $prodEndTime
echo $currentTime
while true
do
if [[ $currentTime -ge $prodStartTime && $currentTime -le $prodEndTime ]];
then
./doSomeWork.sh
else
echo Do Nothing
fi
sleep 600
done
UPDATE: Now I have the code working by checking production timings instead of night mode timings(See edit history). But looks like my script is considering the values as Octal as suggested by "twalberg" in the comments. Could someone help me how to take care of these values?
I simply need a way to ensure that my script runs between the specified time span.
Don't compare them numerically (-ge, -le); just compare them as strings. Since ksh doesn't have >= and <=, you can use the equivalent ! < and ! > instead.
if [[ ! "$currentTime" < "$prodStartTime" && ! "$currentTime" > "$prodEndTime" ]]; then
./doSomeWork.sh
fi
But since we're negating, it might be clearer if we apply DeMorgan's Law and only negate once:
if [[ ! ( "$currentTime" < "$prodStartTime" || "$currentTime" > "$prodEndTime" ) ]]; then
./doSomeWork.sh
fi
In any case, when using < and >, there's no interpretation of the strings as numbers (octal or otherwise) to worry about. As long as all the times have the same number of digits, the string comparison will produce the right answer.
I should be calculating the current time inside the loop. But I have calculated only once outside of the loop and using the same value through out the day.
The script should be like.
#!/bin/ksh
prodStartTime="030000"
prodEndTime="233000"
echo $prodStartTime
echo $prodEndTime
echo $currentTime
while true
do
currentTime=`date +"%H%M%S"`
if [[ $currentTime -ge $prodStartTime && $currentTime -le $prodEndTime ]];
then
./doSomeWork.sh
else
echo Do Nothing
fi
sleep 600
done
Somehow this silly mistake was not visible to my eyes.
You could also do it on easy way..
#!/bin/bash
prodStart="132000"
prodEnd="151500"
while [[ ! $(( `date +"%H%M%S"` )) < "$prodStart" && ! $(( `date +"%H%M%S"` )) > "$prodEnd" ]];
do
echo "Do something..."
done
startTime="80000"
endTime="200000"
curTime=$(date +"%H%M%S" | bc)
echo "startTime : "$startTime
echo "endTime : "$endTime
echo "currentTime :"$curTime
echo "curTime < endTime and curTime > startTime then don't execute"
# Messages will be sent only between 8AM to 8PM
if [[ ! ( $curTime -lt "$endTime" && $curTime -gt "$startTime" ) ]];
then
echo "Don't Execute"
else
echo "Execute"
fi
How can this while loop be limited to maximum 10 retries?
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
sleep 1
done
Keep a counter:
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && break
sleep 1
done
You can also use a for loop and exit it on success:
for try in {1..10} ; do
[[ -d /somemount/share/folder ]] && break
done
The problem (which exists in the other solutions, too) is that once the loop ends, you don't know how it ended - was the directory found, or was the counter exhausted?
I would comment but I do not have enough points for that. I want to contribute anyway.
So this makes it work even if the while loop is nested in another loop. before the break the c variable is being reset to zero.
credits to #anubhava who came up with the original solution.
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && c=0 && break
sleep 1
done
You can use until (instead of "while ! ... break), with a counter limit:
COUNT=0
ATTEMPTS=10
until [[ -d /somemount/share/folder ]] || [[ $COUNT -eq $ATTEMPTS ]]; do
echo -e "$(( COUNT++ ))... \c"
sleep 1
done
[[ $COUNT -eq $ATTEMPTS ]] && echo "Could not access mount" && (exit 1)
Notes:
Just like setting counter as variable, you can set var condition="[[ .. ]]", and use until eval $condition to make it more generic.
echo $(( COUNT++ )) increases the counter while printing.
If running inside a function, use "return 1" instead of "exit 1".
I am attempting to run a block of code if one flag is set to true and the other is set to false. ie
var1=true
var2=false
if [[ $var1 && ! $var2 ]]; then var2="something"; fi
Since that did not evaluate the way that I expected I wrote several other test cases and I am having a hard time understanding how they are being evaluated.
aa=true
bb=false
cc="python"
if [[ "$aa" ]]; then echo "Test0" ; fi
if [[ "$bb" ]]; then echo "Test0.1" ; fi
if [[ !"$aa" ]]; then echo "Test0.2" ; fi
if [[ ! "$aa" ]]; then echo "Test0.3" ; fi
if [[ "$aa" && ! "$bb" ]]; then echo "Test1" ; fi
if [[ "$aa" && ! "$aa" ]]; then echo "Test2" ; fi
if [[ "$aa" ]] && ! [[ "$bb" ]]; then echo "test3" ; fi
if [[ "$aa" ]] && ! [[ "$cc" ]]; then echo "test4" ; fi
if [[ $aa && ! $bb ]]; then echo "Test5" ; fi
if [[ $aa && ! $aa ]]; then echo "Test6" ; fi
if [[ $aa ]] && ! [[ $bb ]]; then echo "test7" ; fi
if [[ $aa ]] && ! [[ $cc ]]; then echo "test8" ; fi
When I run the preceding codeblock the only output I get is
Test0
Test0.1
Test0.2
however, my expectation is that I would get
Test0
Test1
Test3
Test5
Test7
I have tried to understand the best way to run similar tests, however most examples I have found are set up in the format of
if [[ "$aa" == true ]];
which is not quite what I want to do. So my question is what is the best way to make comparisons like this, and why do several of the test cases that I would expect to pass simply not?
Thank you!
Without any operators, [[ only checks if the variable is empty. If it is, then it is considered false, otherwise it is considered true. The contents of the variables do not matter.
Your understanding of booleans in shell context is incorrect.
var1=true
var2=false
Both the above variables are true since those are non-empty strings.
You could instead make use of arithmetic context:
$ a=1
$ b=0
$ ((a==1 && b==0)) && echo y
y
$ ((a==0 && b==0)) && echo y
$
$ ((a && !(b))) && echo y; # This seems to be analogous to what you were attempting
y
The shell does not have Boolean variables, per se. However, there are commands named true and false whose exit statuses are 0 and 1, respectively, and so can be used similarly to Boolean values.
var1=true
var2=false
if $var1 && ! $var2; then var2="something"; fi
The difference is that instead of testing if var1 is set to a true value, you expand it to the name of a command, which runs and succeeds. Likewise, var2 is expanded to a command name which runs and fails, but because it is prefixed with ! the exit status is inverted to indicate success.
(Note that unlike most programming languages, an exit status of 0 indicates success because while most commands have 1 way to succeed, there are many different ways they could fail, so different non-zero values can be assigned different meanings.)
true and false are evaluated as strings ;)
[[ $var ]] is an equivalent of [[ -n $var ]] that check if $var is empty or not.
Then, no need to quote your variables inside [[. See this reminder.
Finally, here is an explication of the difference between && inside brackets and outside.
The closest you can come seems to be use functions instead of variables because you can use their return status in conditionals.
$ var1() { return 0; }
$ var2() { return 1; } # !0 = failure ~ false
and we can test this way
$ var1 && echo "it's true" || echo "it's false"
it's true
$ var2 && echo "it's true" || echo "it's false"
it's false
or this way
$ if var1; then echo "it's true"; else echo "it's false"; fi
it's true
$ if var2; then echo "it's true"; else echo "it's false"; fi
it's false
Hope this helps.