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
  • 4
  • 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](https://unix.stackexchange.com/questions/68694) and [here](https://unix.stackexchange.com/questions/65803). – 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
  • 320,670
  • 36
  • 633
  • 936
  • 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,556
  • 3
  • 23
  • 26