In previous articles, we have seen a number of tricks and techniques that make working at the command line much more productive. However, you can only go so far with a single line - sooner or later, you'll want to automate longer and more complex procedures, and this is where scripting offers a huge payoff.
Scripting lets you automate complex, repetitive or tedious procedures. It also encapsulates knowledge about how things are done – once you've written a script other users can take advantage of it. It eliminates errors due to typographical errors or miss-remembering. In short, scripting is the secret that makes UNIX/Linux systems so much easier to administer.
What Makes a Script?
Essentially, a script is just a text file which contains commands. For example, if you created a file called sysdoc containing the following lines:
/sbin/fdisk -l mount df you could execute it by invoking a sub-shell to run it:
[les@freya les]$ bash sysdoc Cannot open /dev/hda /dev/Volume00/LogVol00 on / type ext3 (rw) [. . . ] /dev/Volume00/LogVol06 on /usr/local type ext3 (rw) /dev/Volume00/LogVol04 on /var type ext3 (rw) /dev/hda1 on /mnt/winc type vfat (rw) Filesystem 1K-blocks Used Available Use% Mounted on /dev/Volume00/LogVol00 507748 260235 221299 55% / /dev/hda3 124443 20062 97955 17% /boot However, having to type bash each time is inelegant - it would be better if you could simply invoke a shell script by typing its name, as for any other program. To do this, you should make the script file executable, with the command:
chmod +x sysdoc This turns on the executable bits in the file's permissions. Now, typing the command
./sysdoc will produce the desired output. A further improvement is to tell the system precisely which shell it should invoke to run the script, by adding a new first line in the script:
#!/bin/bash The '#!' combination is called a 'shebang', and tells a shell, as it starts to execute a script, which shell is required. This is important because a typical UNIX/Linux system has so many different scripting languages. You'll notice, for example, that Perl programs start with '#!/usr/bin/perl', so that the bash shell does not attempt to run them but instead turns control over to the Perl compiler.
The echo Command
You can use the echo command to print strings. For example:
echo 'This is a shell script' Shell Variables
Like most programming languages, shell scripts need to use variables. For the bash shell, variable names must begin with an alphabetic character or underscore, and can also contain numeric characters. You assign a value to a variable with a statement of the form:
name=[value] If a value is not provided, the variable is assigned the null string. So, for example, these are valid variable assignments:
USER=fred WORKDIR=/home/fred infile=numbers.txt prevdir= To obtain the value of a variable, prefix its name with a dollar symbol ($). For example:
echo "Current user is $USER" If you want to remove a variable altogether, use the unset command. You can see all current shell variables with the set command:
[les@freya les]$ set BASH=/bin/bash BASH_VERSINFO=([0]="2" [1]="05b" [2]="0" [3]="1" [4]="release" [5]="i386-redhat-linux-gnu" ) BASH_VERSION='2.05b.0(1)-release' COLORS=/etc/DIR_COLORS.xterm COLORTERM= COLUMNS=80 [ . . .] Most of these variables are set by the various system startup scripts, by the shell startup scripts that run when you log in or create a shell, or by bash itself.
Useful variables:
Environment Variables
Shell variables only exist within the shell itself, but it would be useful if variables could be 'shared' with other programs, particularly programs run by the shell script. You can do this by exporting variables, which makes them environment variables:
export EDITOR
You can assign a value to a variable and export it in one statement:
export DOMAIN=
Now, every program that you start from within this shell, or within this shell script, will inherit its own environment, including copies of all these variables. Notice that this is a copy - if a sub-shell changes any variables, it changes the copies only - the parent shell's environment is unchanged. Shell variables are similarly inherited and copied between shells.
Useful Variables
Quoting, Escaping and Variable Interpolation
If you simply provide a list of words after a command like echo, the shell will treat them as separate arguments. When they are echoed, they will be separated by a single space, regardless of how many spaces separated them in the command line. If you want spacing to be preserved, make the spaces part of the variable by enclosing the entire string in quotes. So:
#!/bin/bash echo Arbitrarily spaced string echo "Arbitrarily spaced string" will produce this output:
Arbitrarily spaced string Arbitrarily spaced string You can use either single quotes (') or double quotes ("), but they behave differently when variables are involved. When a variable is included in a double-quoted string, its value will be interpolated into the string. However, single quotes are stronger - they escape the special meaning of the $ symbol before the variable name, and the variable name - rather than its value - will appear in the string.
You can also escape the values in strings by using a backslash character - of course, if you use a backslash in a single-quoted string, its own special meaning will be escaped.
Command Line Parameters
If you write file and directory names into a script, you will have to edit the script whenever they change. As a rule, it is better to write scripts so that they are more generally usable; this means specifying filenames, directory names, and other parameters at run time, on the command line.
You can pass parameters into a script by referring to them as $0, $1 and so on. $0 is the name of the script itself. You might wonder why you need a variable to hold the name of the script - after all, it will never change and surely you could just permanently write it into the script? However, remember that UNIX filesystems allow a file to have multiple names, through the use of links and symbolic links, so that the same script could be invoked under different names, and could be required to behave differently when so invoked.
There are some special ways to refer to all the command line parameters, with the exclusion of $0:
$* expands to a single variable containing all the command line parameters separated by spaces
$@ expands to a list of separate words, each containing one of the command line parameters
$# is the number of parameters, excluding $0
A Sample Script
Here's a short script that demonstrates some of the techniques covered in this article:
#!/bin/bash # Simple script to record system configuration for log book echo "System Configuration for $HOSTNAME" echo produced at `date` echo ------------------------------------------------------------ echo System Kernel Configuration uname -a echo ------------------------------------------------------------ echo "Disk Partitioning:" /sbin/fdisk -l echo echo "Mounted Filesystems:" /bin/mount echo echo "Disk Space Utilization:" /bin/df echo ------------------------------------------------------------ echo "Network Configuration:" /sbin/ifconfig echo ------------------------------------------------------------ This script can be invoked in several ways:
./sysdoc ./sysdoc | less ./sysdoc | mail -s "System Configuration" user@hostname There are lots of possible enhancements to this script - I'll leave it to you to adapt to your own requirements.
References and Further Reading
For the next article in this series, click here.
Page last updated: 04/Jan/2005 Back to Home Copyright © 1987-2010 Les Bell and Associates Pty Ltd. All rights reserved. webmaster@lesbell.com.au