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, 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. IfconditionA
is true it will executecommand1
and if false it will run theelif
statement and ifconditionB
is true it will runcommand2
. If none of the conditions are true then it skips to the else block to runcommand3
.
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 whenexpressionA
is false, if true, then it proceeds withstatement1
. When false it skips to the else block and then evaluatesexpressionB
which if true will runstatement2
.
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 🙂