1

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.

Example:

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?

!#/bin/bash
name=$(whoami)
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!"
fi
tigger
  • 13
  • 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. – glenn jackman 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 – Stéphane Chazelas 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

2 Answers2

4

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'
fi

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'
fi
Kusalananda
  • 333,661
  • 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
0

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

#!/bin/bash

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

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.

fpmurphy
  • 4,636