Skip to main content

Shell scripting sets apart the scrubs from the pros in the system admin game. With shell scripting under your belt you’ll be automating your system and taking care of business the right way. No more manually re-running the same tasks, or any of that junk. Bust out that terminal because today we are going to learn a thing or too about shell scripting.

The basics

Basic setup

In its simplest form, a shell script is an executable text file that can be as basic as a series of regular console commands up to a more complex script that may include user interaction, conditional statements, loops, etc.

Creating & running a script

To get started with basic scripting the first thing you’ll want to do is create a new sh file using touch, and then give it executable permissions with chmod +x. After which you can edit the scripts’ contents with your favorite text editor.

touch example.sh && chmod +x example.sh

Running a shell script can be done in a couple of ways:

./example.sh 
#or
sh example.sh

The shebang

The top line is a shebang (#!/bin/bash) that indicates what interpreter should be used to parse the scripts contents.

#!/bin/bash

In the above case, you are telling your system to use bash, but any other installed interpreter can be specified in this way, like zsh. Below you’ll find a familiar example (if you read our last bash scripting for development article) of a more complex script. This script uses an if statement to determine if cowsay is installed , then prompts the user for some text before passing that to cowsay and print it out to the terminal

#!/bin/bash
#check for and install cowsay on debian/ubuntu
if ! command -v cowsay &> /dev/null
then
		echo "cowsay not found, installing..."
    sudo apt install cowsay -y
fi
# prompt and run
read -p  "Enter what the cow will say:" p
cowsay -p -s ${p}

Note that the shebang is optional, but it makes your script more compliant with other systems by specifying its needs as running your script without it leaves it up to your system to decide which interpreter to use which could end in disaster. Pro tip: just use a shebang, it’ll save you a lot of headaches in the long run.

Operators

You may have noticed the && operator from earlier posts and articles or more than likely have encountered it out in the wild. && lets you chain console commands together, this is called a logical operator. There are several other operator types that can be used inside of the terminal, both inside and outside a scripting environment. There are many types of operators which could take up an article on their own so we’ll focus on Logical (Boolean) operators since they come up pretty often in bash scripts:

Logical, aka Boolean operators come in three flavors:

  • Logical AND (&&): This operator as described above will return true if both commands evaluate to true. For example:
#!/bin/bash
# the end result is a true statement
mkdir test && cd test
# this will remove the test dir but error out 
# due to test dir no longer existing, returning false
rm test -rf && cd test
  • Logical OR (||): The OR operator will return true if either command is true, in this example the first part will be false but the 2nd command will go through and you’ll get a success message.
rm fakefile || touch another-file;echo success
  • Not Equal to (!): Another programming staple is the Not Equal To (!) unary operator which returns true if the command is false and vice versa.
#!/bin/bash
read -p  "Pick a Number: " n

if [ ${n} != 4 ]; then
    echo "Not Equal"
else
    echo "Equal"
fi

Redirecting Output

Another bit of useful scripting will come from using Pipes, Not to be confused with the Logical OR and Redirection, not to be confused with arithmetic operators to modify command behavior.

Pipes

Up first is the pipe |, this directs the output of your previous command into any other command, for example:

history | grep "docker"

This command will pipe the terminal output (STDOUT) to grep which will parse the command history for all commands that have docker in them.

Redirection

Piping isn’t the only way to capture STDOUT, using > we can take the resulting output and direct that into a text file. Using the above example again we can send the grep output to a file:

history | grep "docker" > cmdhist.txt

We can also append to the end of files using >>.

echo "Hello World" > file.txt
echo "Appended text" >> file.txt

Using variables

Variables in shell scripting are extremely useful bits of code that will let you store/access data or even built-in variables (dependent on your system). You’ll often find variables at the top of script files, not that you don’t have to declare a variable to use it, simply assigning it will create the variable and make it available to use in your script.

#!/bin/sh

username="linuxman"
echo $username

Using echo

The echo directive will spit out whatever you tell it to back out into the terminal. This is useful for making new lines or giving yourself an indicator of progress as your script runs.

#!/bin/bash
echo "hello world!"

In the first example shown above, if cowsay is not installed the script will notify the user via echo and then install the program.

Reading data from the User

Let’s look at the earlier example again. read -p "text" x prompts the user and takes in their input and stores it in a variable that can be called using ${x}. The variable can be named anything you want and you can use multiple prompts and variables in the same script.

read -p  "Enter text to echo" x
echo ${x}

If statements

This next part can get a bit involved but if you are familiar with any programming languages then this next part won’t be a new concept. To jump right into conditionals we’ll focus on 4 different if statements:

  • The if statement has one condition and will execute the command if the expression evaluates to true.
if [condition]
	then
	   command
fi
  • The if-else statement is just like an if statement but with an else block. If true command1 will execute, but if false, then command2 is ran.
if [condition]
	then
	   command1
else
   command2
fi
  • if-elif-else-fi is a multi-conditional statement. It includes two conditions (or more) and introduces the elif statement. If conditionA is true it will execute command1 and if false it will run the elif statement and if conditionB is true it will run command2. If none of the conditions are true then it skips to the else block to run command3.
if [conditionA]
	then
		 command1
elif [conditionB]
	then
		 command2
else
   command3
fi
  • if-then-else-if-then-fi-fi includes a nested if block that will be executed when expressionA is false, if true, then it proceeds with statement1. When false it skips to the else block and then evaluates expressionB which if true will run statement2.
if [conditionA]
then
   command1
else
   if [conditionB]
	   then
	      command2
   fi
fi

Checking if user is sudo

Here’s a practical example of a simple if-statement to determine if a user has sudo privileges.

#Check if Sudo
if [ `whoami` != root ];
	then
		echo "Run as root or using sudo"
		exit
else
   sudo apt update && sudo apt upgrade -y
fi

Looping

Up next is looping statements! Loops will add another layer of logic to your scripts. We’ll briefly look at 3 looping statements used in shell scripting.

  • while statement In a while statement the condition is evaluated, and if true the loop will process and execute the commands until the initial condition returns false and the loop will terminate. If false from the get-get go the loop will never run.

Warning! Like in every other programming language it is very easy to create an endless loop so make sure your logic checks out before you run a script with a while loop!

while [condition]
do
   command1
   command2
   command3
done
  • for statement The for loop is an incredibly useful tool to make short work of groups/arrays of items. Inside of a for loop, a command is ran on every item in the list, until there are not more items in the initial grouping to run the command on.
for OUTPUT in $(command)
do
    command1 on $OUTPUT
    command2 on $OUTPUT
done

The last one we’ll look at is the until statement.

  • until statements run until the given condition is false.
until [condition]
do
  command
done

Not the most glamorous part of scripting, I know, but getting these concepts under your belt will open the door up for endless scripting possibilities!

Spicing up your scripts

Using ANSI colors

This next section is great if you want to differentiate script output with colors which is very useful if you are dealing with multiple console outputs. In order to use ANSI colors inside of your scripts you need to define the colors that you’ll want to use inside the script. Below you’ll find a color cheat sheet that will fast track your color scripting!

#!/bin/bash

# Ansi color code variables
red="\\e[0;91m"
purple="\\e[0;35m"
blue="\\e[0;94m"
cyan="\\e[0;36m"
green="\\e[0;92m"
white="\\e[0;97m"
black="\\e[0;30m"
yellow="\\e[0;33m"

#resets text color to default
reset="\\e[0m"

#define bg
bg="\\e[K"

#Colored backgrounds
blue_bg="\\e[1;104m${bg}"
red_bg="\\e[1;101m${bg}"
white_bg="\\e[1;47m${bg}"
purple_bg="\\e[1;45m${bg}"
cyan_bg="\\e[1;46m${bg}"
green_bg="\\e[1;42m${bg}"
black_bg="\\e[1;40m${bg}"
yellow_bg="\\e[1;43m${bg}"

# colored text
echo 'Colored Text:'
echo -e "${yellow}Hello World!${reset}"
echo -e "${red}Hello World!${reset}"
echo -e "${purple}Hello World!${reset}"
echo -e "${blue}Hello World!${reset}"
echo -e "${cyan}Hello World!${reset}"
echo -e "${green}Hello World!${reset}"
echo -e "${white}Hello World!${reset}"
echo -e "${black}Hello World!${reset}"

#new line
echo ""

#  Colored Text over Colored Background
echo 'Colored text over colored background:'
echo -e "${yellow}${red_bg}Hello World!${reset}"
echo -e "${red}${yellow_bg}Hello World!${reset}"
echo -e "${purple}${blue_bg}Hello World!${reset}"
echo -e "${blue}${purple_bg}Hello World!${reset}"
echo -e "${cyan}${green_bg}Hello World!${reset}"
echo -e "${green}${cyan_bg}Hello World!${reset}"
echo -e "${white}${black_bg}Hello World!${reset}"
echo -e "${black}${white_bg}Hello World!${reset}"

Using text styling

Another way you can stylize your text output is by using text styles. These text effects are self-evident, below you’ll find another cheat sheet detailing its usage.

#!/bin/bash

#Demo colors
red="\\e[0;91m"
white="\\e[0;97m"
blue="\\e[0;94m"

bold="\\e[1m"
uline="\\e[4m"
reset="\\e[0m"

echo "Bold text:"
# bold colored text
echo -e "${red}${bold}Hello World!${reset}"
echo -e "${white}${bold}Hello World!${reset}"
echo -e "${blue}${bold}Hello World!${reset}"

echo ""
echo "Underlined text:"
# underlined colored text
echo -e "${red}${uline}Hello World!${reset}"
echo -e "${white}${uline}Hello World!${reset}"
echo -e "${blue}${uline}Hello World!${reset}"

echo ""

# Colors across multiple lines
echo -e "\\"${white}Some folks are born"
echo "made to wave the flag"
echo -e "oooh, that ${red}red${reset}, ${white}white, and ${blue}${bold}blue.${reset}\\""

Now that you’ve gotten a fairly broad introduction in the world of scripting, go on out there and be somebody! Scripting is one of the coolest things you can do to get your system, server, or whatever to do exactly what you want, when you want. Most importantly this makes you a power user, which as we all know, is what we should all strive to be. Thanks for reading now go out there and script something 🙂

Leave a Reply