Search code examples
linuxbashopensuse

Bash while loop between two times


I am trying to write a bash script that will loop if the time is after certain time and before a certain time. Here is what i have got but it gives me an error;

#!/bin/bash

while [ date +"%T" -gt '06:00:00' && date +"%T" -lt '21:00:00'];
  do
  ##echo `php mainstatquery.php`
  echo "Hello World";
  sleep 5;
done

and this is the error

./timer.sh: line 3: [: missing `]'

If anyone could point me in the right direction.


Solution

  • Here's an easy way to understand your while problems:

    The [ is an actual Unix command. Do ls /bin/[ and you'll see. It's a link to the /bin/test command. Do a man test from the command line and see the various tests that can be done.

    What the while does is execute the command you give it, and if it returns a zero exit status, the while statement is considered true and the statement will continue. You can do things like this:

    while sleep 2
    do
       echo "I slept for two seconds"
    done
    

    All the test command does is do some sort of testing (file tests, tests of equality, etc.) and return a zero if the statement is true and a non-zero otherwise:

    $  test 2 -gt 3
    $ echo $?
    1   <- That statement is false
    
    $ [ 2 -lt 3 ]   #The test command using square brackets
    $ echo $?
    0  <- That statement is true.
    

    Take a look at the manpage for test and you'll see all valid tests. This:

    while [ date +"%T" -gt '06:00:00' && date +"%T" -lt '21:00:00']
    

    is the same as

    while test date +"%T" -gt '06:00:00' && date +"%T" -lt '21:00:00'
    

    Let's go through a few things here:

    • date + %T is not a valid operator for the test command.

    The test command can't execute a command internally. What you need to do is to put that command in $(..) and probably use quotes to play it safe. Thus:

    while test "$(date +"%T")" -gt '06:00:00' && "$(date +"%T")" -lt '21:00:00'
    
    • The && is not a valid operator in the test command. What you probably want is -a which is the and conjunctive for stringing together two tests in test.

    This would give you:

    while test $(date +"%T") -gt '06:00:00' -a "$(date +"%T")" -lt '21:00:00'
    
    • There are two separate greater than test operators for comparisons. One is for strings and one is for integers. The -gt is the test for integers. Since you're dealing with strings, you need to use >:

      while test "$(date +"%T")" > '06:00:00' -a "$(date +"%T")" < '21:00:00'

    As an alternative, you could have also used the && conjunctive instead of -a, but each side of the && would have to be separate test statements:

    while test "$(date +"%T")" > '06:00:00' && test "$(date +"%T")" < '21:00:00'
    

    Now, let's convert the test syntax back to [...] because it's easier on the eyes

    while [ "$(date +"%T")" > '06:00:00' -a "$(date +"%T")" < '21:00:00' ]
    

    OR

    while [ "$(date +"%T")" > '06:00:00' ] && [ "$(date +"%T")" < '21:00:00' ]
    

    By the way, the internal [[...]] is better -- especially with the > sign since it can be interpreted by the shell as a file redirect.

    while [[ "$(date +"%T")" > '06:00:00' -a "$(date +"%T")" < '21:00:00' ]]
    

    OR

    while [[ "$(date +"%T")" > '06:00:00' ]] && [[ "$(date +"%T")" < '21:00:00' ]]