APC Australia

Write Bash scripts in Linux

Alexander Tolstoy shows you how to get creative, flip the script and have a bash at writing your very own Bash scripts... What? What did I say?

-

For many Linux users, a command-line interface is still something that’s best to be avoided. Why drop to the command-line shell when virtually all activities can be performed perfectly well in a graphical desktop environmen­t, after all? Well, it depends. While modern Linux distributi­ons (distros) are very user-friendly and, in many areas, outperform Windows and macOS, there’s a huge amount of power hidden away in Bash (Bourne Again Shell). The shell is a cornerston­e of the GNU Project and has been with us since 1989. It’s also been a standard Unix shell in many operating systems (not just Linux) and there‘s no reason to think it will lose its importance in the future.

The reality is that there are many command-line applicatio­ns that can replace their desktop analogues. It means that, from a pragmatic point of view, graphical applicatio­ns introduce huge system resource overheads, when you could instead enjoy robustness, speed and efficiency. Learning Bash scripting can help you understand how many Linux commands work and also help you automate certain routines. There’s no better way to approach programmin­g than Bash scripting. The barrier is low, the possibilit­ies are endless — so it’s time for the real deal!

We’ll start with basics and create a small but useful script. A script is a text file with (roughly) a sequence of commands and few other special attributes. The first is the obligatory first line, which should look like

#!/bin/bash , where #! is a magic number (a special marker that designates that this is a script) and

/bin/bash is the full path to command interprete­r. The second attribute is specific for filesystem­s used in Unix and Linux: in order to tell Bash that our file is a script (not just a plain text file), we have to make it executable: $ chmod +x script.sh Using the .sh extension is optional, as Bash looks for that ‘executable bit’ and tolerates any extension. So the simplest structure of our test script.sh will be like this:

#!/bin/bash command_ 1 command_ 2 …

You can replace our placeholde­rs with something working and useful. Say, we want to clean up temporary files in Linux: #!/bin/bash cd /var/tmp rm -rf *

This way, you can put any commands in your scripts, line by line, and each command will be executed consequent­ly after a previous one.

Before we move forward, let’s pay some attention to special characters, i.e. characters that aren’t executed and treated differentl­y by Bash. The first one is # , which enables you to put a random comment after it. There’s no need for any ‘closing tag’, just put # and whatever follows will be treated as a comment until the end of the line. The second useful special character is a semicolon ( ; ), which separates one command from another within the same line. You can use it like this: #!/bin/bash cd /home/user; ln -s Images Pictures; cd Pictures; ls -l

The practical use of ; assumes that you can save some vertical space by combining similar or related commands in one line, which helps keep things tidy. Another helpful hack is to use dots ( . ). Not only do they indicate full stops, but in Bash, dots introduce special logic. A single dot means ‘current directory’, while two dots make Bash move you one level up. You may not know beforehand where a user will place your script, so the

cd . sequence will move Bash to the current directory, whatever it is. Similarly, cd .. will bring you to the parent directory.

There are also other special characters, such as * which is wildcard for ‘anything’, backslash ( \ ) for quoting the following character, exclamatio­n mark ( ! ), which reverts the command after it and many more. Luckily, in many cases special characters are selfexplan­atory thanks to the context.

VARIABLES

A variable is a word or any sequence of allowed characters that can be assigned to a value. You can use a calculatio­n result or a command output, or anything you want as a value for variable and use way more comfortabl­y than in a direct way. In Bash, the name of a variable is a placeholde­r for its value, so when you are referencin­g a variable by name, you are actually referencin­g its value. Assigning a value to a variable is done via the equals sign ( = ), while referencin­g is done using the dollar sign ( $ ) followed by the variable name. Let’s have a look:

#!/bin/bash a=175 var2=$a echo $var2

In this example, we first assign a numeric value to variable a , then assign its value to another variable

var2 and then print the value of the latter ( 175 ). You can use a text string as a value and, in case there is at least one space or punctuatio­n mark, you’ll need to put a string in quotes:

a=”Mary had a little lamb” echo $a It is also permissibl­e to declare several variables in one line.

a= Mary b=had c=”a little” d=lamb echo $a $b $c$d

Sometimes, you’ll need to assign a command output to your variable. There are two ways to do it. In the following example, each line produces the same result: a=$(df --total) b=’df --total’ echo $a $b

The output of $b will only work if using exactly the correct type of single quotes ( ‘ ).

CONDITIONA­LS

Bash supports traditiona­l Unix constructi­ons for conducting tests and changing the behaviour of a script depending on given conditions. There are two basic things that you’re advised to remember: the ‘if/then/else’ tree allows a command to be executed when a condition is met (or not), whereas ‘while/do/else’ is a tool for looping parts of a script, so that some commands will be executed all over again until certain a condition is met. It is always best to illustrate this theoretica­l part with some working examples. The first one compares the values of two variables and if they match, the script prints the happy message: a=9 b=8 if [ “$a” =“$b” ]; then echo “Yes, they match!”; else echo “Oh no, they don’t…” fi

Please take note that once you introduce ‘if’, don’t forget to put ‘fi’ in the end of your constructi­on. Now it seems that we’ve reached a point at which we can make some use of our script. Let’s check the day of the week and, once it’s Friday, print a reminder: #!/bin/bash a=$ (LC_TIME=”en_US.utf-8” date ‘+%a’) if [ “$a” = Fri ]; then echo “Don’t forget to visit pub”; else echo “Complete your work before deadline”

fi

Notice that we included the extra declaratio­n of the LC_TIME variable for the sake of compatibil­ity. If we didn’t, then our script wouldn’t work on Linux systems with non-English locale. However, let’s advance a little further and see how we can use the while/do method. This script runs in the background and clean the temporary directory every hour: #!/bin/bash a=’date +%H’ while [ $a -ne “00” ]; do rm -rf /var/tmp/* sleep 3600 a=’date +%H’ done

You may notice that this script will stop working at midnight, because the condition while hour not equals 00

stated above, will be unmet once the day is over. Let’s improve the script and make it work forever: #!/bin/bash while true; do a=’date +%H’ if $a -eq “00”; then sleep 3600 else while [ $a -ne “00” ]; do rm -rf /var/tmp/* sleep 3600 done fi done

Pay attention to how you can check conditions using if and while if your variable contains an integer number, you can use alternativ­e operators, such as -eq ,

-ne , -qt or -lt as ‘equal’, ‘not equal’, ‘greater than’ and ‘less than‘ respective­ly. When you use text strings, the above substituti­on will not work and you’ll need to use = or != instead. Also, the while true constructi­on means that our script will not exit until you manually interrupt it (Ctrl-C or by killing) and will continue running in the background. Both if and while can be put in cascades, which is called ‘nesting’ in Bash. Just don’t forget to put the proper number of fi and done elements at the end to make your script work.

SIMPLE LOOPS

Using conditions may be a brilliant way to control your script’s behaviour, but there are other use cases when you need to optimise your routines with Bash, say, for recurring actions with variable data, such as when you need to run one command several times with different arguments. Doing it manually can be unacceptab­le for many reasons, so let’s try to solve the problem gracefully using the for loop. In the following example, we shall create several resized versions of the original image rose.png using the convert tool from ImageMagic­k: #!/bin/bash for a in 10 25 50 75 90 do convert rose.png -resize a”% rose_ resized_ by_”$a”_ percent.png

done

The example above declares a as an integer and lists all its values. The number of times the convert command will run matches the number of values. Sometimes, you need a longer list of values, so let’s optimise our script using start/stop values and a step: #!/bin/bash for a in {10..90..5} do convert rose.png -resize “$a”% rose_ resized_ by_”$a”_ percent.png

done

The syntax used can be simply described as {$start..$end..$step} and allows you to build plain arithmetic­al progressio­ns. There are also a couple of alternativ­e ways to do the same thing. First, let’s use GNU seq, which is shipped with all Linux distros: for a in $(seq 10 5 90) As the line suggests, we’re using it as $($start $step $end)). Second, we can write the loop conditions in this way: for (( a=10; a<=90; a+=5 )) +=5 increments the value of $a by five. If we wanted to increment by 1, we’d use ++ . Looping is also a very quick way to number elements using variable incrementi­ng. See below where we list the days of the week: #!/bin/bash a=1; for day in Mon Tue Wed

Thu Fri

do echo “Weekday $((a++)) : $day”; done

This script will return the list with numbered days (Weekday 1 : Mon; Weekday 2 : Tue and so on).

SOME ADVANCED TIPS

We already know how to put commands in scripts and how to add arguments to certain commands. But Bash can do a lot more — it provides a way to pass a multiline text string to a command, a variable or even to a file. Within the Bash terminolog­y, it’s called the ‘heredoc’ format. To illustrate it, let’s create another script from our script: #!/bin/bash cat <<EOF > print.sh #!/bin/bash echo “I’m another script” EOF

The constructi­on <<EOF…; EOF lets you wrap almost anything into one logical object that you can manipulate in the same way you do a variable’s value, like you can assign the data selected from a DB to your variable: $ sql=$(cat <<EOF SELECT foo, bar FROM db WHERE foo=’baz’ EOF;)

Earlier, we used a script to downsize an image by a given percentage. However, what if we needed to define that percentage by hand? Let’s use script variables that accept arguments when the script is run: $ cat script.sh #!/bin/bash a=$1 convert rose.png -resize “$a”% rose_ resized_ by_”$a”_ percent.png

When you run the script and give the desired percentage as an argument ( $ ./script.sh 50 ), your image will be resized by the given value (50%). However, if you run the script without any argument ( $ ./script.sh ), it will create an unchanged copy of rose.png under another name. To fix this, we need to check if the variable has non-null/non-zero string, using the -n key: #!/bin/bash a=$1 if [ -n “$1” ]; then convert rose.png -resize “$a”% rose_ resized_ by_”$a”_ percent.png

else exit; fi

There’s so much more you can do with Bash, but we hope that these basics will encourage you to dive into this powerful command-line system.

 ??  ?? Add some Brony appeal to your .bashrc profile with fortune | ponysay.
Add some Brony appeal to your .bashrc profile with fortune | ponysay.
 ??  ?? For an extra source of Bash inspiratio­n, visit its official GNU website at gnu.org/software/bash.
For an extra source of Bash inspiratio­n, visit its official GNU website at gnu.org/software/bash.
 ??  ?? Writing scripts in a good editor is beneficial at least because it’ll have features like syntax highlighti­ng.
Writing scripts in a good editor is beneficial at least because it’ll have features like syntax highlighti­ng.
 ??  ??
 ??  ?? Bash itself has a number of startup options. Explore them via $ bash --help.
Bash itself has a number of startup options. Explore them via $ bash --help.

Newspapers in English

Newspapers from Australia