I am new to Gnu/Linux and bash, and I am trying, unsuccessfully, to write a simple bash script to test if date +%H is within a predefined range of hours.


hour='date +%H'
if [[ $hour -ge 12 ]] || [[ $hour -lt 19 ]]
then echo "Good afternoon!"

Trying to isolate a line to this results in "integer expression expected":

test $hour -ge 12

It feels like I'm missing something simple to either have $hour return as integer or just handle it as a string.

Edit: Here's the completed script, any necessary improvements on the basic level?

hour=$(date +%H)
if [ $hour -lt 5 ] || [ $hour -ge 19 ]
then xmessage -center "Good evening $name!"
elif [ $hour -ge 5 ] && [ $hour -lt 12 ]
then xmessage -center "Good morning $name!"
else xmessage -center "Good afternoon $name!"
  • 1
    You have to be careful with comparing dates: at 8am or 9am, date +%H will return 08 or 09 -- and then bash arithmetic will complain about "value too great for base" because those are invalid octal numbers. Use date +%_H to get space-padded hours instead of zero-padded hours. Dec 17 '20 at 17:42
  • @glennjackman Or use the non-standard but commonly available %k (hour, 0-24).
    – Kusalananda
    Dec 17 '20 at 17:44
  • 1
    With zsh: (){print Good ${argv[2+($1>11)+($1>18)]}.} ${(%):-%D{%H}} morning afternoon evening Dec 17 '20 at 18:03
  • @StéphaneChazelas Or zsh -c 'what you just wrote' from the bash shell...
    – Kusalananda
    Dec 17 '20 at 18:04
  • 1
    Regarding your recent update: Yes, the #! at the start of the first line should read nothing but #!. Yours is swapped. Also, I would quote all variable expansions, and use printf to output variable data. See here and here.
    – Kusalananda
    Dec 17 '20 at 18:26

You are assigning the literal string date +%H to the variable hour.

To run that date command and to assign the output of it to hour, use a command substitution:

hour=$(date +%H)

Alternatively, with a recent release of the bash shell (4.2+),

printf -v hour '%(%H)T' -1

would do the same thing without using date at all.

Also, you need fi to go with that if and use && ("and") in place of || ("or") to get the logic correct:

if [ "$hour" -ge 12 ] && [ "$hour" -lt 19 ]; then
    echo 'Good afternoon'

I'm using the standard [ ... ] test rather than the bash shell's own [[ ... ]] test here to avoid issues with values of $hour being interpreted (in an arithmetic context introduced by the -ge and -lt tests) as invalid octal numbers (08 and 09).

If you feel you need to use [[ ... ]] you may test ${hour#0} instead of the unmodified value of $hour to avoid issues. The value of ${hour#0} will be the same as $hour but with any single leading 0 removed.

if [[ ${hour#0} -ge 12 && ${hour#0} -lt 19 ]]; then
    echo 'Good afternoon'
  • Perfect, command substitution and having the incorrect || vs && was the issue. No need for [[ ... ]] specifically vs [ ... ] based on your explanation. I'm working off basic slides from my class and hadn't learned the difference in the two yet and appreciate the extra info!
    – tigger
    Dec 17 '20 at 18:15

Bash also supports the ((...)) syntax for arithmetic operations. Your code can be rewritten as:


declare -i hour=$(date +%k)
if (( hour > 12 && hour < 19 ))
    printf "Good afternoon\n"

The line declare -i hour=$(date +%k) specifies that the variable hour is to be treated as an arithmetic integer and assigns the current hour (0-23) to it with no leading zero.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.