Intro
Basic Setup
In its simplest form, a shell script is an executable text file. It can be as basic as a series of regular bash commands up to a more complex script. One that may include file or directory interaction, conditional statements, loops, etc.
Creating & running a script
touch example.sh && chmod +x example.sh
./example.sh
#or
sh example.sh
The shebang
The top line is a shebang #!/bin/bash
. That indicates what interpreter should get used to parse the scripts contents.
#!/bin/bash
In the above case, you are telling your system to use bash to interpret the script. Any installed interpreter gets specified in this way. For example if we were using zsh
, then it would look like this: #!/bin/zsh
. Below you’ll find a example of a more complex script (a familiar one, if you read my previous bash post) . This script uses an if statement to determine if cowsay
is currently installed. It 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}
Operators
You may have noticed the &&
operator from earlier posts or have likely encountered it out in the wild. &&
is a logical operator that lets you chain commands in the terminal together. There are several other operator types. If you do any kind of development you’ve likely used some of them. There are many types of operators which could take up an article on their own. So instead 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 will return true if both commands return true. For example:
#!/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}
- 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 (|
). Don’t confuse this with the Logical OR operator which uses two pipe characters (||
). A singular pipe will allow you to control the output of any program on the command line.
Pipes
Up first is the pipe |
, this directs the output of your previous command into any other command, for example:
history | grep "docker"
The above example will pipe the terminal output (STDOUT
) to grep
. This will parse all your 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
#!/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!"
Lets look back at the first example. 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 gets called using ${x}
. Name your variables anything you want. You can use any number of 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. If you are familiar with any programming language then this next part won’t be a new concept. To jump right into conditionals we’ll focus on 4 different if statements:
- if statement have one condition. They will execute the command if the expression evaluates to true.
if [condition]
then
command
fi
- The if-else statement is like an if statement but with an else block. If true
command1
will execute, but if false, thencommand2
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. 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.
The nested if statement gets executed when expressionA is false. If true it then proceeds with statement1. When false it skips to the else block and then evaluates expressionB. If true it 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 look at 3 looping statements used in shell scripting.
- In while statements the condition gets evaluated. If true, the loop will run and execute the commands until the initial condition returns false. 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. Make sure your logic checks out before you run a script with a while loop!
while [condition]
do
command1
command2
command3
done
- The for loop is a very 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. This gets done until there are no 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
Spicing up your scripts
Using ANSI colors
This next section is great if you want to differentiate script output with colors. This is very useful if you are dealing with many console outputs. 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 var
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 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 doing exactly what you want, when you want. Above all 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 🙂