Display minutes instead of 1m

Is there a way that this script could display minutes instead of 1m ? Same with hours. Thanks.

#!/bin/bash
#
# Sound alarm after specifying time and message
# Must input time delay AND message in double quotes !!
#
#
# ** sleep can also accept intergers ex. sleep 7.63
# Made alias for it type al

Red='\e[0;31m'
BRed='\e[1;31m'
BIRed='\e[1;91m' # ${BIRed} this works
Gre='\e[0;32m'
BGre='\e[1;32m'
BBlu='\e[1;34m' # ${BBlu}
BWhi='\e[1;37m'
Black='\e[0;30'
BWhite='\e[0m 1;37'
# This defines a variable containing the ANSI escape sequence to clear
RCol='\e[0m';

soundfile="/usr/share/sounds/My_Sounds/Alarm_Clock_Sound.mp3"
clear
# amixer -D pulse sset Master 20% > /dev/null 2>&1
if [ -f "$soundfile" ];
then
echo -e "${BGre}Soundfile is present."
else

echo "File $soundfile does NOT exist."
echo
echo "Program will now exit."
exit
fi

[ -z "$2" ] && {
echo
echo -e " ${BIRed}Error!! No time value given and/or message specified !!"
echo
echo -e " ${BBlu}Alarm Program 2018 ${RCol}"
echo
echo -e " alarm.sh [time value in seconds] Message in double Quotes";
echo -e " alarm 5m = 5 minute alarm"
echo -e " alarm 5h = 5 hour alarm"
echo -e " alarm 5d = 5 day alarm"
echo -e " alarm 1.5m = 1 minute 30 seconds alarm"
echo
echo -e " alarm.sh 1m "\"Tea is ready."\""

echo
exit 1; }
echo -e "\033[30;5mTIMER COUNTING DOWN to $1 \033[0m"
sleep $1
{
for ((volume = 15; volume <= 70; volume += 2)); do
# 2> /dev/null suppresses messages for amixer AND (c)vlc
amixer -D pulse sset Master ${volume}% > /dev/null
sleep .5s
done
} &

mpg123 $soundfile > /dev/null 2>&1

amixer -D pulse sset Master 70%

gxmessage -fg blue -font 'sans 20' -timeout 2 ' Tea is ready. !!'
sleep 3s
clear

please show examples of this script being invoked and the desired output from those

Why is the script checking whether $2 is given as the "time value", when $1 is actually supposed to be the time value, and $2 is a "message"?

And to answer your original question - yes, it's possible to display e.g. "1 minute" instead of "1m", and e.g. "5 hours" instead of "5h" - just type in the first argument e.g. "5 hours" (exactly like this, in quotes) and convert this input to a value that sleep understands (before running the sleep command with defined time)

One possible solution could be:

#[...]
echo -e "\033[30;5mTIMER COUNTING DOWN to $1 \033[0m"
sleep_timer=$(sed -r "s/^[^0-9]*([0-9]*\.?[0-9]+) *([smhd]).*/\1\2/" <<<"${1,,}")
[[ "${sleep_timer}" =~ ^[0-9]*\.?[0-9]+[smhd]$ ]] && sleep $sleep_timer
#[...]

Converting this the other way round, e.g. for entered 5m to display as 5 minutes it would require some additional condition checks, but it should be possible as well.

1 Like

Thanks.

This is not showing the quotes.

echo -e "   alarm ""5 minutes"   = 5 minute alarm""

Easier way if need to print ". I wasn't sure which quotes you like to see, but here examples how to do it.

echo -e '   alarm "5 minutes"   = 5 minute alarm'

Or take of "special meaning"

echo -e "   alarm "\"5 minutes\"   = 5 minute alarm\""
1 Like

With bash builtins (no need to run sed):

[[ "${1,,}" =~ ([0-9]*\.?[0-9]+)\ *([smhd]|$) ]] || {
  echo "Unrecognized time value: $1"
  exit 1
}
sleep "${BASH_REMATCH[1]}${BASH_REMATCH[2]}"

The [[ ]] puts (group) matches in the BASH_REMATCH array.
Where BASH_REMATCH[0] is the total match.
BTW ${1,,} yields the lowercase $1.

1 Like

In Bash, I tend to use printf over echo -e (they are both built-ins), and put the format in single quotes (which escape double quotes), and the args in double quotes (which escape single quotes). printf also has proper formatting and special character opportunities. Backslash is my least favourite character.

$ mins=15
$ printf '   alarm "%s minutes   = %s minute alarm"\n' "${mins}" "'${mins}'"
   alarm "15 minutes   = '15' minute alarm"
$
1 Like

Hi @cyclist,

instead of enclosing the strings by the color codes each time, you could define some simple functions per color, e.g.:

red() { echo -e "\e[${2:-0};31m$1\e[0m"; }
green() { echo -e "\e[${2:-0};32m$1\e[0m"; }
lgreen() { echo -e "\e[${2:-0};92m$1\e[0m"; }

That could be generalized for all colors and attributes, and passing the attribute number is a bit ugly. There are various ways to change that (e.g. by defining one function per color and attribute or defining an assoc array), but this example is intended to be simple.

And instead of many single echos you can use Here Documents (see man bash):

#!/bin/bash

red() { echo -e "\e[${2:-0};31m$1\e[0m"; }
green() { echo -e "\e[${2:-0};32m$1\e[0m"; }
lgreen() { echo -e "\e[${2:-0};92m$1\e[0m"; }

cat << EOMSG
here doc with:
$(lgreen "light green") text
  indented $(red "bold red" 1) text
$(red "italic red" 3)
empty line:

EOMSG
echo "embedded $(green "green") text"
green "complete green line"

Btw you only need -e for echoing strings that contain special escaped chars like \t (hor. tab) or \n (new line). printf does that by default, but it doesn't print a newline by default (like echo -n).

When you post a code block, you should enclose it by triple backticks, not each line. See Markdown Cheat Sheet | Markdown Guide.

2 Likes

How can I get the double quotes to show for 1 second and ready?

echo -e " test.sh ""1 second"" "ready""

echo -e " test.sh "\"1 second\"" \"ready\""
test.sh "1 second" "ready"

# more madness

echo -e " test.sh \"1 second\" \"ready\""
 test.sh "1 second" "ready"

# and so on

echo -e  test.sh \"1 second\" \"ready\"
test.sh "1 second" "ready"

as others have mentioned .... printf is the way to go
ex:

someTime=4 ; printf ' test.sh "%s second" "ready"\n' "${someTime}"
 test.sh "4 second" "ready"

Quotes pair, they do not nest. These eight quotes just stitch together five strings:

" test.sh " => space test.sh space
"1 second"
" " => space
ready #..(which is not in quotes at all)
"" => an empty string

Doubling up the quotes does not work: that is a CSV-only trick.

If there are no shell expansions in the text, put the whole string in single quotes:

$ echo -e ' test.sh "1 second" "ready"'
 test.sh "1 second" "ready"

If you need shell expansions, you need to switch those to double quotes in the middle.

$ echo -e ' test.sh "'"${foo}"' second" "ready"'
 test.sh "1 second" "ready"

Notice that is three quoted string in close proximity:

' test.sh "'
"${foo}"
' second" "ready"'

As I explained yesterday, separating the fixed and variable parts by using printf with a format string and arguments is far easier to use.

2 Likes

It looks like there is more than one way.

Linux has quite a variety of ways. :slight_smile:

echo -e " Ex. alarm.sh \"3 minutes.\" \"Tea is ready.\""

indeed, as I (and others) have shown

I'd use a 'string' for the constants:

echo 'Ex. alarm.sh "3 minutes" "Tea is ready."'

For variables I'd use

time="3 minutes"
message="Tea is ready."
me=${0##*/}
printf 'Ex. %s "%s" "%s"\n' "$me" "$time" "$message"

A $variable is recognized only in " "

1 Like

Quotes (generally) get stripped by the shell after it has used them to delimit strings, which is what you generally intend.

Backslashes are somewhat trickier. They are removed after they have done their job. But if a string is evaluated twice (perhaps entered once as a string and then used as a pattern), then you often need to escape the backslash with another backslash.

So you end up writing "\\n" (or possibly "\\\n") to get the string "\n" which then evaluates as a newline (and yes, I had to type five backslashes here in this post to get three visible ones).

I detest making the same error more than once in my life, so I only use backslash where it is bullet-proof. Typically, I might declare ASCII characters with ANSI-C Quoting (Bash Reference 3.1.2.4), like SOH=$'\001'; ESC=$'\033'; which is good for readability as well as syntax. Then I can expand those variables in shell, or pass them to awk with -v.

Of course, avoiding backslash means I won't ever get to be an expert with it.

Use the inline triple-backticks:

``` \\\n ```

I wrapped it in triple-backticks lines (makes a code block) for demo. Now without:
\\\n
There is another icon at the top of the editor window, it looks like >_

While back-slashing and "escaping the escapes" are all valid alternatives, but they can get quite tedious to keep up - one would need to squint really hard to see what's happening....
One alternative I found useful (and it might not be related to the issue at hand) is bash's printf '%q' formatting. From man bash:

              %b     causes printf to expand backslash escape sequences in the corresponding argument in the same way as echo -e.
              %q     causes printf to output the corresponding argument in a format that can be reused as shell input.
              %Q     like %q, but applies any supplied precision to the argument before quoting it.
              %(datefmt)T
                     causes printf to output the dateā€time string resulting from using datefmt as a format string for strftime(3).  The  correspondā€
                     ing  argument  is  an  integer representing the number of seconds since the epoch.  Two special argument values may be used: -1
                     represents the current time, and -2 represents the time the shell was invoked.  If no argument is specified, conversion behaves
                     as if -1 had been given.  This is an exception to the usual printf behavior.

              The %b, %q, and %T directives all use the field width and precision arguments from the format specification and write that many  bytes
              from (or use that wide a field for) the expanded argument, which usually contains more characters than the original.

another alternative is to use the "Inline No Parse" icon on the editor window that looks like a "crossed equal sign" and which expands to FOUR back-ticks.