We all know how tedious it can be to perform the same long command over and over again.
And sometimes you might not even know how to issue commands or know how they work exactly.
And when this needs to be performed the same way it might just be better if you could make a script specific to your needs.
But you may have other preferences too. Perhaps you need to perform this task at certain times, or perhaps you need to have it performed by someone else who isn’t very confident on the command line.
Luckily enough, Linux has Bash as the main scripting language built in, which is perfectly suited for just such cases.
You could write a Python script, but if it’s basic system maintenance then Bash will get the job done. And because of it’s scripting nature, it means you can write the code needed once, and perform it whenever you want, much like Batch on MS-DOS used to be (remember that?).
But Linux has more tools at your disposal which can all be combined to make your life so much easier, and I will be using all the ones that will be most useful to you.

Take for instance the Cron utility.
Cron is a utility which will run certain programs, scripts or anything for that matter, at certain intervals, in a way that is simple but very powerful.
And when you write a small script to perform a certain task and hand it over to Cron, it will carry that out at the moment you have specified. Whether once a day, once a week or even once an hour. You can forget setting your alarm to perform the task, and just let Linux deal with it.

And thanks to the great efforts of the GNOME team and KDE team, we also have great programs like Zenity and KDialog at our disposal.
These programs allow you to create a nice neat GUI for your bash script depending on which desktop you use (GNOME/Unity using Zenity, KDE using KDialog).
Unlike using Glade in combination with Python for instance, you can issue the GUI building commands directly into your script in an easy to understand way, which means you have one file which produces both the GUI and carries out the command you need.
Very handy for those who don’t feel comfortable with the command line, and if you just want a script to look nice.

In part 1 we will be looking at the absolute beginners steps.
How to write a basic bash script, then spice it up with some user input, and finally make it smart with some conditional for, while and if loops.
And at the end we will see how we can use that to automate a task. In our example we will make a 4 line script (or 1 line if you want to use semi-colons) to batch convert WAV files to MP3s.

But let’s start at the beginning, and write a couple of small bash scripts.

1. Writing a small Bash script

Bash scripts can be as complicated as you make them, but also be extremely simple.
And if you are comfortable working in the terminal, can navigate through the filesystem using the terminal, and issue commands there, you already know a lot of the basics. The simple commands ‘cd’, ‘rm’, ‘mkdir’, ‘touch’, and ‘ls’ are all bash commands, so you can use them inside your script as if you were on the command line.
But there may be some commands that you rarely use whilst working on the command line which you might require in a script.
Such examples may include ‘echo’ for displaying information, variables, and ‘read’ to take input.
As is tradition, we will begin with a simple Hello World script.
All that this script will do is clear the screen and show the text ‘Hello World’

So start by opening a text editor like Gedit and copy the following text there, once pasted, save it in your home directory under the name ‘hello_world.sh’:

#!/bin/bash

# This will display Hello World

clear
echo “Hello World!”

Then, simply open a terminal and navigate to the directory in which you saved this script, in our case we should be in that directory already. Then issue the command (without the quotes) ‘bash hello_world.sh’

See what happened? The screen cleared and it displayed ‘Hello World!’ after which the application quit.
So, what did we do exactly?

The first line in this script is known as the shebang (#!/bin/bash).
What this line does is tell where it can find the bash program to run this script in.
This is particularly handy when we forget to give the script a .sh ending and then it can still be run as normal.
The /bin/bash element is the location of bash on the filesystem.

The next line begins with a hash (#) which denotes a comment line.
Anything written after the hash will not be interpreted by bash and is used to leave a comment about what something does.
It’s quite irrelevant here, but in a long script that can be complicated, it is useful to explain what each part does, making it easy to make changes and simply to understand.

The first real command we have issued is the ‘clear’ command.
This command will fill the screen with enough whitespace to appear as if the screen has been ‘cleared’, this makes it much cleaner than a cluttered program.
As with all commands, you can try it out in a terminal outside of a script and it will still do the same job.

Finally the line ‘echo “Hello World!”‘ displays Hello World!
Echo is the command that simply tells the system that the following string (or variable) has to be displayed, and a string can be put in either single or double quotes.
If we replace the word World with You, and save it, it will display ‘Hello You!’.

2. Bash with interactive input and variables

The example above was simple enough, but sometimes we require some input from the user.
For that we require variables, and in the next example the ‘read’ command.
The read command will take user input and store it in a variable.
If you don’t know what that is, imagine a box. You can then take information, and store it in that box. Whenever you reference that box, you take what’s inside it out. That is how variables work, but a variable can only contain one piece of information at a time, make sure to remember that.

In the next example, we transform our Hello World script to instead say hello to whoever is using the script.

#!/bin/bash

# Asking for user name

clear
echo “What is your name? ”
read name
echo “Hello $name!”

Please note there is a space between name? and the double quotes.
If you run this script it will ask for your name and when you have given it, it will say Hello and then your name and an exclamation mark.
For instance if I give my name as Arthur, it will say ‘Hello Arthur!’.

The first line is the shebang as we previously discussed.
After the comment it will once again clear the screen.
Then it will simply display the question ‘What is your name?’, but by having a space behind it, it means that your answer won’t appear right behind the question making it look clearer.
Next we get the command ‘read name’.
What happens here is that the command read knows to take input from the user, and the ‘name’ behind it is the variable. Therefore, the user input gets stored in the variable ‘name’. We can later call upon ‘name’ to get the input.

The next line ‘echo “Hello $name!”‘ does that.
As we discussed earlier, echo displays a string on the screen, but we did something clever here. We first provided Hello as part of the string, but right behind it we put $name. Whenever you call upon a variable you have stored something in, you place a dollar sign in front of it, so the variable ‘name’ get’s called using ‘$name’, or if you used the variable ‘hello’ it would be called upon using ‘$hello’ etc.
What it therefore does is take the information stored in ‘name’ and displays it as part of the string.
Clever isn’t it?

3. Meeting conditions with IF, WHILE and FOR loops.

If you aren’t a programmer, then this bit may have seemed confusing in the past, so I will try my best at explaining what this is.
Within programming and scripting, there is a lot of loops being used.
What these do is check for a certain condition to be met.

The IF loop may for instance ask for your age, and then it checks IF a person is below 18, it will run a certain command, but IF a person is above 18 it will run a different command altogether. ELSE if a person didn’t give an age, well, then a totally different command gets issued.

The WHILE loop checks if a condition is still the same as before. So WHILE something is the same, the same command gets issued, ELSE, it may quit.
This is handy if we want to keep a program running about 5 times. So WHILE we are only on run number 4 we keep going, ELSE we stop.

The FOR loop runs similar to the WHILE loop, but a little more specific at the basic level
For instance, we can specify certain numbers we want the FOR loop to run in, it will then keep going through the loop trying to meet what we specify and stop when it’s done. Hopefully the example for this later will give some clarification to this difficult to explain loop.

Why not use these examples altogether to see how we can use them with our Hello World example script to make it more and more detailed.
This is going to look overwhelming to the previous examples, but don’t worry, all will become clear.

#!/bin/bash

# A more detailed Hello World script

clear
end=0

while [  “$end” -eq 0 ]
do

echo “How old are you? ”
read age

if [ “$age” -gt “17” ]
then
echo “What is your name? ”
read name
for i in `seq 1 $age`
do
echo “Hello $name, you are $1 years old!”
end=1
done
else
echo “You are too young to run this!”
end=1
fi
done

First of all, this is not really the most beautiful of code and things could have been done differently, but, it illustrates the loops perfectly, whilst still being somewhat useful and easier to understand what each bit does.

The first lines are the familiar shebang, comment and clear lines.
But then we get ‘end=0’.
We use this for our example while loop, since we could use this to keep a program running (we aren’t in this example). We place the number 0 in a variable called end for later use.

Now we arrive at our first loop, the WHILE loop.
‘while [ “$end” -eq 0 ]’ looks scarily complicated, but really it isn’t.
let’s first deal with the ‘-eq’ bit.
It is simply short for ‘equal to’, and since we have place the conditions of a loop inside these brackets “[ ]”, it translates to:
While the information stored in variable ‘end’ is the same as 0.
So the script will keep checking to see if indeed ‘end’ is still a 0.
And then the next line states simply  ‘do’ to finish of our command.
So, while ‘end’ is a 0, do….

The next line is just a printed line that asks for your age.
And right below that, we are asking for user input and storing that in the variable ‘age’.
Notice how inside a loop, we leave a gap of space (just press tab), to make it easier to read.

Now we arrive at our next loop, this time the IF loop.
We are now going to see whether a condition is met or not.
‘if [ “$age” -gt “17” ]’
As before, let’s first look at -gt.
This simply means ‘greater than’, or bigger than.
As I mentioned before, we put the conditions that have to be met inside the brackets and we quote both the variable to match and what to match it to in quotes.
Then it translates to:
if the number we stored in ‘age’ is bigger than the number 17.
And the next line states ‘then’, to tell what is to happen.
So as you can see, it simply checks the number that we type in and checks to see if it is bigger than 17, if that is the case, then we go to the next bit.
But beware, greater than, does not mean including a number. For instance if you wanted to check if it was less than (smaller than) with -lt on 17, then it would not include 17, it would mean 16 and below. To include 17 you would then use, less than and equal too, in bash that would be -le (Less and Equal).

Inside that loop if the condition was met we arrive at our next part.
We first display the question of your name on the screen. Then, on the next line, we take the user input and place it in the variable ‘name’.
So far so good.
But now we arrive at our final loop, the difficult to explain FOR loop.

for i in `seq 1 $age`
Looks intimidating doesn’t it? And where did that ‘i’ come from.
Well it’s actually fairly straight forward.
The ‘i’ is a temporary variable we are going to use (could be anything but ‘i’ tends to be the traditional variable to use).
Then the seq is short for sequence. What For loops do is run through a sequence until the conditions no longer apply.
After having stated ‘seq’ we give our starting point at which to loop, in our case: 1.
After that we give our end number at which to stop, in our case we gave the variable ‘age’.
All this inside quotes (the ones on the key above the tab key, not regular quotes).
Let me replace the variable so you can see what it does.
Say we gave our age as 19.
What it then really says is ‘for i in `seq 1 19`’
And if we translate that, it means, that it will run in a sequence from 1 to 19, every time using the variable ‘i’, which becomes clear in a moment.
After the do command, you see ‘echo “Hello $name, you are $i years old!”‘

As you can see, it displays ‘Hello’ and the name given, after that it displays ‘you are … years old!’.
Remember how we gave the variable ‘i’ to the for loop?
What it now does is it begins with giving variable ‘i’ the value of 1 (since that’s where we said we want our sequence to begin), it then runs through this loop and then displays ‘you are 1 years old!’, then it goes back to the top and reaches number 2 in the sequence, and changes variable ‘i’ to 2, and then displays ‘you are 2 years old!’.
This will happen all the way until it reaches the last number in the sequence. In our case it’s in a variable, so whatever age we gave in. After that it stops. Therefore, you will see a fair few lines with ‘You are … years old!’ each line 1 year up.
We also added ‘end=1’.
Remember right at the beginning that we gave ‘end’ the value of 0? And how we told the while loop to keep running this entire program as long as ‘end’ was equal to 0?
Well, at this point the variable is changed to 1, so the while loop condition is no longer met, and the program is allowed to quit.

Since the For loop is done, we have to close it off, we do this by using the ‘done’ command.
Now you see ‘else’, if you look carefully at the structure, you will notice it is in the same line vertically as the beginning of our IF loop, this means that the ELSE condition is part of the IF loop.
Inside of ‘else’ we simply display that you are too young to run this.
We knew this because we told the IF loop to check if the variable ‘age’ was greater than 17.
And the ELSE statement acts when that condition isn’t met (in this case when ‘age’ is smaller than or equal to 17).
After that, it changes the ‘end’ variable to a 1 to allow the while loop to finish and stop our program.

If you took out all the ‘end=1’ parts, then the program would keep running.
At the end of the IF loop, we put ‘fi’ to end the loop, and at the end of the while loop, we use ‘done’ to close it off.

4. Using loops with commands

But this is all about automating tasks, not hello worlds.
We can use these loops to automate a task however, in little ingenious ways.
For instance, have you ever had a .wav file that you wanted to change to an MP3 file?
That’s all fair and well, but what if you had 100’s of them?
The annoying bit isn’t only the manual conversion, but you have stupid new names like 1.mp3, 2.mp3 3.mp3 etc.
What if you wanted to batch convert the whole lot, and keep their original names while you were at it?
Well, why not use the FOR loop for this?!

Say you have the command  ffmpeg -b 192k -i abc.wav abc.mp3 which converts the abc.wav to abc.mp3.
Handy right?
We can make it a batch conversion command using a for loop.

for i in *.wav
do
ffmpeg -b 192k -i “$i” “${i%.wav}.mp3”
done

Instead of giving a number for a sequence in a for loop, what we did is say *.wav.
The asterisk (*) means anything or all. So in this case it means any file ending in .wav.
So what we are doing is we are telling the script to run through all files that end in .wav.
The first file it encounters automatically gets placed in variable ‘i’.
Then it runs the ffmpeg command on it, and if you replace all the variables ‘i’ with what is contained in it, you will get something like the following, if your file was abc.wav:

ffmpeg -b 192k -i abc.wav abc.mp3

You might be confused by the whole ‘${i%.wav}.mp3’ thing.
This bit basically removes the .wav bit and replaces it with .mp3, so the name stays in tact but instead it’s an mp3 file.
You could also put it all in one line. Just place a semi-colon (;) behind the end of every command.
This one would become: for i in *.wav; do; ffmpeg -b 192k -i “$i” “${i%.wav}.mp3”; done

Try some out for yourself

Why not try some out for yourself
In part 2 we will be looking at introducing Cron.
We will try and automate our scripts even further by letting the system take care of them. Write it once, never need to run it again by hand will be the motto.

I hope you have enjoyed this tutorial, and keep an eye out on part 2

Advertisements