Search code examples
regexbashshellposixemoji

Is the use of regex here POSIX compliant and is the code used appropriate for the problem described?


Following from my previous question here, please see below a fuller form of my question.

Code use case

The current code is a module for use in polybar, a customisable status bar. As per the first link, polybar is drawn using a configuration file and each bar that is called (by, for instance, running the polybar mybar) reads the configuration file for any given modules. A full example can be seen here. Custom or user defined modules are loaded by calling the relevant script file. For instance:

[module/test]
type = custom/script
exec = some/script/file
tail = true

Polybar accepts, at the very least, shell scripts and python scripts (and perhaps others, though I have not tested this). For the purposes of this question, I am concerned with the appropriateness of my shell script and not its interface with polybar (which currently works as expected; though as @EdMorton explains, this may not be intended functionality, hence this question).

Current code

The following is a minimal working example of my code.

#!/bin/bash

smile=#d1dadf;
sad=#ff5833;
angry=#1a88a4;
laugh=#daf7a6;

while true; do

    # get hour
    time=$(date +%_H -u);

    # set empty hour
    timeShow=TEST;

    # set empty emoji
    emoji=;

    if [ $time -ge 0 ] && [ $time -lt 6 ];
    then
            emoji=%{F$smile}😀%{F-}
    elif [ $time -ge 6 ] && [ $time -lt 12 ];
    then
            emoji=%{F$sad}😢%{F-}
    elif [ $time -ge 12 ] && [ $time -lt 18 ];
    then
            emoji=%{F$angry}😡%{F-}
    elif [ $time -ge 18 ] && [ $time -ne 0 ];
    then
            emoji=%{F$laugh}😆%{F-}
    fi

    if [[ "$emoji" =~ [😢] ]];
    then
        ((timeShow = time - 1))
    elif [[ "$emoji" =~ [😡] ]];
    then
        ((timeShow = time - 2))
    elif [[ "$emoji" =~ [😆] ]];
    then
        ((timeShow = time - 3))
    fi

    echo "$timeShow:$(date '+%M' -u) $emoji"
    
    sleep 1
done

Explanation of inputs (and outputs)

Running the script as is requires no input (the output is calculated from within the script itself). Hence running the script is simply done via:

./script.sh

The output should (and does) return the formatted time, along with the emoji wrapped in colour format tags, as described above.

The program as it stands takes the current UTC hour from date. This value (stored in the variable time) is then modified and stored within timeShow. Assuming a particular range of hours (and hence emoji), the script then modifies timeShow by either subtracting 1, 2, or 3. The emoji are found in the string emoji by performing a regex operation to locate the character, which is wrapped by colour formatting.

Expected output given hardcoded input

Changing the following:

 while true; do... done

To this:

for time in 8 12 22 0; do... done

In addition, the following lines should be changed to match below:

# get hour
#time=$(date +%_H -u);

# set default hour
timeShow=0

Should give the following as expected outputs, assuming the script is run on the hour.

Loop 1 (at 8 am) (offset of -1):

7:00 %{F#ff5833}😢%{F-}

Loop 2 (at 12 pm) (offset of -2):

10:00 %{F#1a88a4}😡%{F-}

Loop 3 (at 10 pm) (offset of -3):

19:00 %{F#daf7a6}😆%{F-}

Loop 4 (at 12 am) (offset of 0):

0:00 %{F#d1dadf}😀%{F-}

Desired output

The script works as intended. As mentioned above, however, this may not be accidental. The purpose of this question is to understand whether the approach used is producing the correct output, or only happens to do so. The regex at present isolates the character by using the [😀]. For any glyph which may comprise 2 or more characters, M-bM-^XM-^A$ for instance, isolating the emoji thusly, [😀] is potentially inaccurate as it would match the first corresponding character, leading to undesirable or unexpected behaviour. Further explanation of this problem is provided here.


Solution

  • Instead of matching $emoji with a regexp, set another variable when you're setting emoji, and use that when setting timeShow.

    #!/bin/bash
    
    smile=#d1dadf;
    sad=#ff5833;
    angry=#1a88a4;
    laugh=#daf7a6;
    
    while true; do
    
        # get hour
        time=$(date +%_H -u);
    
        # set empty hour
        timeShow=TEST;
        timeOffset=0
    
        # set empty emoji
        emoji=;
    
        if [ $time -ge 0 ] && [ $time -lt 6 ];
        then
                emoji=%{F$smile}😀%{F-}
                timeOffset=3
        elif [ $time -ge 6 ] && [ $time -lt 12 ];
        then
                emoji=%{F$sad}😢%{F-}
                timeOffset=1
        elif [ $time -ge 12 ] && [ $time -lt 18 ];
        then
                emoji=%{F$angry}😡%{F-}
                timeOffset=2
        elif [ $time -ge 18 ] && [ $time -ne 0 ];
        then
                emoji=%{F$laugh}😆%{F-}
                timeOffset=3
        fi
    
        timeshow=$((time - timeOffset)
    
        echo "$timeShow:$(date '+%M' -u) $emoji"
        
        sleep 1 &
        wait
    done