I had my wisdom teeth removed this morning, and I’ve more or less been bedridden with my laptop, so I decided to kill time and keep my mind off of the pain by writing a script to beep whenever I have to alternate between having ice on my face and vice versa. I’m supposed to switch between the two every 20 minutes, which is a pain to remember and keep track of, so why not have the computer do that for me? Most of the work is already done for me in readily available tools, like Linux‘s “date” command, and the MOC console audio player. The only “real” work I had to do was write a few simple conditional statements, look into command line arguments for the programs used (using man pages), and creating a beeping sound using Audacity. This took me less than 30 minutes total, and I figured someone somewhere might find it useful or interesting, so I decided to write a tutorial about it and describe how I did it. A lot of this is geared towards those without much programming experience, so it might be useful in teaching the basics of programming and turning logic into code. Note: I realize there is a “beep” command available, but my laptop does not have a built-in speaker that works with that, so this is a very easy alternative, and it’s more compatible, too.
Because the easiest step is creating the audio file, I’ll start with that. If you’re just looking for a short beeping sound, and you don’t feel like opening up Audacity, the file I used can be downloaded below.
Audio File Used: 440Hz Beep for 3 Seconds
This is actually incredibly easy. If you don’t already have Audacity, download and install it. Now open it up, and choose “Tone” under the “Generate” menu. For me, the settings I used were Waveform: Sine, Frequency: 440Hz, Amplitude: 1, Duration: 3 Seconds. This will quickly generate the beeping sound. Now you need to export this in a format playable by MOC. To do this, go to File > Export… and set the file type to “Ogg Vorbis Files“. Now save the file as something.ogg in the same directory you want the script to be in. For my script, the file name I used is “beep-440-3s.ogg”, but the name really doesn’t matter. I don’t recommend using spaces as you probably have to escape them in your script, which is a pain that can easily be avoided.
Now, if you don’t already have MOC console audio player installed, you need to install it (or another tool of your choosing) in order to play the audio file from the command line. To get MOC audio player in Ubuntu or Debian Linux, you can type the following command in a terminal, assuming the debian package “moc” is available in your configured software repositories:
sudo apt-get install moc
This method requires super-user (administrative) permissions, unfortunately, but that probably won’t be a problem for you. For more information on the sudo command, see Ubuntu Linux, Day 18: What Is This ‘sudo’ You Speak Of? (pcworld.com). Excuse me for a second, my timer just went off… now that we got that over with, let’s get started on coding the script!
Now, In my case, because I have to switch between ice and no ice every 20 minutes, there are three times that I switch between the two as 60 divided by 20 is 3. Because this is an odd number, the range minutes that I will or will not have a bag of ice on my face alternates every hour. To determine whether or not I should have a bag of ice on my face in a given 20 minutes, we can use the modulus operator, which is used to determine the remainder of a division operation. If the modulus operator returns a zero, then there is no remainder (obviously). By getting the remainder of dividing the number of the hour by 2, we can tell if the current hour is even if the remainder is zero. The way I wrote this script isn’t the most efficient way of doing this, but I wanted to create something that worked quickly without spending too much time on it. Also, yes, I realize I could’ve done something incredibly simple, like using the watch command to tell me when to alternate between ice and no ice, but this was more fun to code, mostly for practice, and it works for me. An example of how I would use the watch command instead is to have it wait 20 minutes (the argument ‘n’, which is the time to wait, is in seconds, so there are 1200 seconds in 20 minutes), and play the sound after that amount of time. This can be done with the following command from within the folder where the beep audio file is stored, substituting the duration and the file name with the ones you used/need:
watch -n 1200 mocp -l beep-440-3s.ogg
This will wait 20 minutes from the time of starting the command and then beep, repeating every 20 minutes. However, the title of this guide is “How To Make a Beeping Timer Using Bash Script and Ubuntu”, so I’m going to show you how to do that.
First, we’ll start with the obligatory shebang line:
Because the entire script will be repeated indefinitely, until closed (such as using Ctrl + C), we want the main contents of our script to be in a while loop. The bash equivalent of a “while (true)” loop is “while [ 1 ]“, so the entire body of the script will be enclosed in that loop. Instead of brackets, while loops in bash are terminated with “do” at the beginning, and “done” at the end. The most obvious challenge we need to focus on is getting the current hour and minute in a format that’s incredibly easy to parse and work with. Linux’s “date” command works wonderfully for this. It does nearly all of the work for you, all you have to do is tell it how to format the date. If you look through the man pages for the date command, you can see that you’re able to specify how to format the date. All we’re interested in is the current hour (%k) and minutes (%M). To retrieve the hour from the date command, you simply type “date +%k”, where the formatting we want is after the plus sign. Go ahead and try that. The command to retrieve the current time in minutes is the same thing, substituting “k” for “M”. The letters are case-sensitive. When initializing a variable using bash script, it’s possible to set the variable to the return value (output) of a command using back-ticks. So, to get the current hour and minute, our code looks like this:
Now that we have the hour and the minutes, we need to check to see if we should play the beep audio file or not. If the remainder of dividing the current minutes by 20 is zero, then we should be playing the file. The code for this is as follows:
let REM=”$MIN % 20″
if [ $REM = 0 ];
mocp -l beep-440-3s.ogg
The “-l” argument of the mocp command tells MOC to just play the audio files specified in the command line arguments without messing with playlists, etc. Now that we have the beep working, we could consider the script done, as it goes off every at :00, :20, and :40 after the hour, but other that the fact that it’s obvious if you should put on ice or take it off, it’s a coding challenge to determine which one, so I decided to make the program say whether you should put ice on or vice versa. The first thing I did is realized that there are three times in an hour where I alternate between ice or not. Two of the times are the same except for the middle time at 20 minutes. Because 20 / 20 is one, we can check if the current minutes divided by 20 is 1 and display whether or not to put ice on depending on if the hour is an even number or not. In my code, I refer to the current minute divided by 20 with a truncated remainder as the current “set” number. The code for this is easy to write:
For debugging information, I list the current hour, minute, set, and whether I should have ice on or not on the screen. This is also easy to code:
echo -n “Hour: $HOUR Min: $MIN Set: $SET “
In the string echoed to the console and the mathematical expressions, a variable name preceded by a dollar sign ($) is replaced with the value of that variable and evaluated as such. The -n argument of the “echo” command just tells echo not to append a new line character to the end of the string it prints to the output stream (in this case the console). The reason for this is because later in this script I echo whether or not I need to have ice on or off, and it looks neater to have it all on the same line. To determine whether the hour is an even number or not, we get the remainder of dividing the hour by two. If the remainder is zero, the hour is even. We can then use that to help determine whether we alternate cycles this hour. The code for this is incredibly simple:
let hrem=”$HOUR % 2″
As stated earlier, if the set is the middle set (set ’1′, at 20 minutes after the hour), whether or not I need to use ice is different than the other two sets. Using that logic as well as the fact that the fact that the cycles alternate each hour, we can piece together the logic using very basic conditional statements:
if [ $SET -ne 1 ]; then
if [ $hrem -ne 0 ]; then
echo “Ice On”
echo “Ice Off”
if [ $hrem -ne 0 ]; then
echo “Ice Off”
echo “Ice On”
If you aren’t familiar with bash syntax, “-ne” is short for “is not equal to”, which is usually expressed in other languages using “!=”, or “not” before a condition. Finally, to prevent a lot of redundant output, we will use the sleep command to wait a minute (60 seconds in the command) before the next iteration (repetition) of the while loop:
sleep 60s #wait 1 minute
And we’re finally done coding the script! Now, we just need to save the script in the same directory as the beep audio file, with the “.sh” file extension and set it as executable. To do that, you can use the Properties dialog, or just do it with the command prompt using the following command:
chmod +x ice-timer-script.sh
Now you can run the script using the command “sh ice-timer-script.sh“. I hope that somebody finds this tutorial useful. Writing this certainly helped keep me busy, since I’ve been in bed for the majority of the day. If you have any questions or feel that anything needs clarification, feel free to leave a comment! The final script used in this tutorial can be found at http://code.dylanmtaylor.com/bash/ice-timer-script.sh.