Americas

  • United States
sandra_henrystocker
Unix Dweeb

Basic scripting on Unix and Linux

How-To
Mar 10, 20218 mins
LinuxUnix

If you're not yet comfortable with writing scripts on Unix and Linux systems, this post might get you off to a healthy start.

rules procedures manuals programming language
Credit: Thinkstock

Creating a script on a Unix or Linux system can be dead easy or surprisingly complex; it all depends on how much you’re trying to get the script to do. In this post, we look at scripting basics—at how to get started if you have never built a script before.

Identifying the shell

Unix and Linux systems today have a number of shells that you can use. Each shell is a command interpreter. It reads commands and sends them to the kernel for processing.

Bash is one of the most popular, but there’s also zsh, cshtcsh and korn. There’s even one called fish that can be especially nice for Linux beginners because of its helpful command auto-completion options. To determine which shell you are using, use this command:

$ echo $SHELL
/bin/bash

You can also determine your primary shell by checking the /etc/passwd file:

$ grep $USER /etc/passwd
nemo:x:1111:1111:Nemo the Fish:/home/nemo:/bin/bash   

One way to determine what shells are available on a Linux system is to check the /etc/shells file.

$ more /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/bin/zsh
/usr/bin/zsh
/usr/bin/screen
/usr/bin/tmux
/usr/bin/fish

The system shown above claims to have nine available shells.

Which shell is best for any indifidual depends largely on what they’re used to using since much of the syntax in scripting does not represent the commands that you will find in /bin, /usr/bin or /usr/local/bin. Instead, they are part of the shell itself and are called “built-ins”. This includes the commands used for looping (e.g., for and while).

One easy choice for scripting is to use whatever shell you use on the command line since, after all, you’ll be more or less comfortable using it.

Selecting your shell

To determine which of the available shells will run the commands in your script, make the first line of your script look like one of these:

#!/bin/sh
#!/bin/dash
#!/bin/bash
#!/bin/rbash
#!/bin/zsh
#!/usr/bin/zsh
#!/usr/bin/screen
#!/usr/bin/tmux
#!/usr/bin/fish

When the first line of your script identifies the shell to be used, that shell will run the commands in the script. If you do not include the shell as the first line in a script, the shell you use when you invoke the script will be the one that runs it.

Running a command

Any command you run on the Linux command line can be run in a script provided it’s compatible with the specified shell. Use your favorite text editor and type in your commands. Here’s a very simple script that shows the current date in a day-month-year format. I call this script  “today”.

#!/bin/bash

date +”%d %B %Y”

To run it …

$ today
08 March 2021

Adding a comment

It’s a good idea to add comments to scripts that explain what a script is meant to accomplish—especially when a script is long or the syntax is complicated. Just start the comment with a # sign. Comments can be lines by themselves or added to the end of commands in the script. For example:

#!/bin/bash

# display the date/time repeatedly in a loop
while true
do
    echo -n “still running ...”
    date
    sleep 300	# sleep 5 minutes
done

Making the file executable

To make a script executable, use the chmod command and make sure that the intended users can run it. For example:

$ chmod 700 myscript	# you can run it
$ chmod 755 myscript	# everyone can run it

If a script isn’t set up to be executable, it can still be run using the “.” built-in that “sources” (i.e., reads and runs) the script.

$ . today
08 March 2021

Using an if command

The if command allows you to test conditions or variables. In this example, we check to see if the script is being run on a Friday.

if [ `date +”%A”` == Friday ];then
    echo “TGIF!”; 
fi

The basic syntax for an if command is “if value == other_value”. The == performs a comparison, and it’s necessary to ensure that the shell sees one value on each side of the comparison operator. For this reason, you often have to put your strings in quotes of some kind.

Understanding variables

Just to be sure this is clear, it’s important to understand that variables are assigned in one way and referenced in another. Assign a variable with just its name, but precede the name with a to use it.

$ favnum=11
$ echo $favnum
11

Prompting the user for input

To prompt a user within a script to enter some information, you need to provide both the prompt and the command to read what the user types. You should also assign a variable name that makes sense as in this example. Note that using the echo -n command means the user will enter their response on the same line as the prompt is displayed.

echo -n “How many loops?> “
read numloops

The person running the script will see the prompt and provide their response:

How many loops?> 11

Using command line arguments

To make use of arguments that a user enters along with the script name, you need to know how to identify them. Script arguments will be assigned the names $1, $2 and so on. For any argument that you’re going to use repeatedly, you might consider assigning those values to more meaningful variable names.

$!/bin/bash

if [[ $1 != [0-9]* ]]; then
    echo “Error: $1 is not numeric”
    exit
else
    loops=$1
fi

In this case, we’re checking to be sure that the first argument provided is numeric and exiting the script if it is not. If the response is numeric, we then assign it to the variable $loops to use later in the script.

Another useful thing to do in a script is to first verify that there are arguments. Otherwise syntax like what is shown above would fail because the shell would see “if [[ != [0-9]* ]];” which would generate a syntactical error.

To check that the number of arguments provided is correct, you could use syntax like the following that checks to be sure at least two arguments have been provided and, otherwise, reminds the user that both a number of lines and file name are required:

#!/bin/bash

if [ $# -lt 2 ]; then
    echo “Usage: $0 lines filename”
    exit 1
fi

Different ways to loop

There are a number of ways to loop within a script. Use for when you want to loop a preset number of times. For example:

#!/bin/bash

for day in Sun Mon Tue Wed Thu Fri Sat
do
    echo $day
done

or …

#!/bin/bash

for letter in {a..z}
do
   echo $letter
done

Use while when you want to loop as long as some condition exists or doesn’t exist.

#!/bin/bash

n=1

while [ $n -le 4 ]
do
    echo $n
    ((n++))
done

Using case statements

Case statements allow your scripts to react differently depending on what values are being examined. In the script below, we use different commands to extract the contents of the file provided as an argument by identifying the file type.

#!/bin/bash

if [ $# -eq 0 ]; then
    echo -n “filename> “
    read filename
else
    filename=$1
fi

if [ ! -f “$filename” ]; then
    echo “No such file: $filename”
    exit
fi

case $filename in
    *.tar)      tar xf $filename;;
    *.tar.bz2)  tar xjf $filename;;
    *.tbz)      tar xjf $filename;;
    *.tbz2)     tar xjf $filename;;
    *.tgz)      tar xzf $filename;;
    *.tar.gz)   tar xzf $filename;;
    *.gz)       gunzip $filename;;
    *.bz2)      bunzip2 $filename;;
    *.zip)      unzip $filename;;
    *.Z)        uncompress $filename;;
    *.rar)      rar x $filename ;;
    *)          echo “No extract option for $filename”
esac

Note that this script also prompts for a file name if none was provided and then checks to make sure that the file specified actually exists. Only after that does it bother with the extraction.

Reacting to errors

You can detect and react to errors within scripts and, in doing so, avoid other errors. The trick is to check the exit codes after commands are run. If an exit code has a value other than zero, an error occurred. In this script, we look to see if Apache is running, but send the output from the check to /dev/null. We then check to see if the exit code isn’t equal to zero as this would indicate that the ps command did not get a response. If the exit code is not zero, the script informs the user that Apache isn’t running.

#!/bin/bash

ps -ef | grep apache2 > /dev/null
if [ $? != 0 ]; then
    echo Apache is not running
    exit
fi

Wrap Up

Scripts on Linux system can help ensure that complicated processing is done in a consistent manner and makes running a series of commands a lot less trouble.

sandra_henrystocker
Unix Dweeb

Sandra Henry-Stocker has been administering Unix systems for more than 30 years. She describes herself as "USL" (Unix as a second language) but remembers enough English to write books and buy groceries. She lives in the mountains in Virginia where, when not working with or writing about Unix, she's chasing the bears away from her bird feeders.

The opinions expressed in this blog are those of Sandra Henry-Stocker and do not necessarily represent those of IDG Communications, Inc., its parent, subsidiary or affiliated companies.