Bash Scripting Adventures at UTS

With my father telling me that UNIX was old and that ‘no one uses it anymore’, I made the tough decision last week and decided to choose UNIX Systems Programming as my last elective for my degree. My mother, who would have otherwise never heard of UNIX, chimed in, mentioning its appearance in the 1993 movie, Jurassic Park. Little did I know that the UNIX system there is real

But I digress, although it’s still early days and we’re still mostly covering content I vaguely remember from Web Systems from my first year of university and other commands picked up these last couple of years, it’s a good refresher. We’ll be focusing on UNIX for the next few weeks, before we move onto Ruben’s favourite, Perl.

Starting off, some bash scripting some of you may remember from Web Systems. I always liked the shebang we used then (#!/bin/bash), but when moving between my Mac’s system and different Linux systems, portability is a serious consideration, as Ruben has mentioned somewhere before.

#!/usr/bin/env bash

Taking arguments

There are two ways of allowing scripts to take an argument, you can either place it after the command to run the script, or you can have the script ask for input before it tries to do anything. I prefer to do the latter, because I often forget what the scripts are written are for, so it helps to have the prompt when I try to run it.

Method 1 is pretty simple in that you can just start to include the arguments you expect in the code. Usually you’ll call them $1 and $2, so on.

#!/usr/bin/env bash

# This is an example of shell variables $1 $2
echo 'The variables $1 and $2 store the first 2 arguments.'
echo "There values are $1 and $2."
echo "These can be used as arguments to a command."
ls -l  $1
ls -l  $2

Single quotes prints the first echo just as a sentence without printing the temporary variables ($1 and $2).

Method 2 is a bit more difficult, but still rather straightforward. Use read to store the user’s input in a variable (which is filename here) — it is a bash builtin command, but only reads one line unless you give it other arguments. To call on this variable later, you need to use the $ sign (ie. $filename), but it’s not used while storing something into the variable.

#!/usr/bin/env bash

# This is an example of the read command.

echo "Enter a file name:"
read filename
ls -l $filename

Hold on, variables?

You can set variables pretty simply, though they are usually in CAPS, or uppercase to most people. There are shell variables and environment variables. A shell variable holds a value in a memory storage area that can be used by the current shell, but will be lost if the user closes the session.

% VARIABLE=varies
% echo $VARIABLE

An environment variable, however are special shell variables visible to all programs executed under shell. To see what current ones you have, you can use env, and to add a shell variable as an environment one, use export. Be wary of overwriting things like your PATH though or you may find that many of your commands stop working.

% export VARIABLE

But there are other types of variables, so let’s just see them in use:

#!/usr/bin/env bash

# Output script name
echo "This script is called: $0"
# Output number of arguments passed to script
echo "This script has had $# arguments passed to it"
# Output values of all arguments passed to it
echo "The values passed were $*"

Like so, running it with bash rather than ./ just to make it pretty. Either works though, usually.

-bash-4.0$ bash 1 2 3 4
This script is called:
This script has had 4 arguments passed to it
The values passed were 1 2 3 4

Using manly pages

When it’s all said and done, bash scripting isn’t too hard so far as long as you can work around putting variables into many commands you would use normally — scripting saves you effort. You can find a lot through man pages, yet I simply never seem to find anything I need in them. For some things, maybe Google works better — when it’s allowed anyway.

Some more command examples for referencing.

#!/usr/bin/env bash

# Take one command line argument which is a file name
echo -e "Enter a file name: \c"
read filename

# Display summary of named file
# File type, permissions, number of lines, words, bytes,
# first 3 lines, last 2 lines

echo "File type:"
file $filename

echo "File permissions:"
ls -l $filename

echo "Number of lines:"
wc -l $filename

echo "First 3 lines:"
head -3 $filename

echo "Last 2 lines:"
tail -2 $filename

Fun Trivia

Just some fun things which helped me out along the way with this:

  • -e with echo interprets special parts of its string/argument. For example \n to add a new line, and \c to not go to a new line.
  • ` ` delimiters tell the shell to execute command entered there before executing the shell script itself. Output of the command is captured and pasted in (command substitution).
  • & tells a command to run in the background.

There were a few more things, but that’s all I’ll belabour you with this time. ;) I think that’s enough for now.