Skip to content

Linux: Automated Tasks with Shell Scripting

Parameter Expansion

Parameter Expansion is a way to substitute the value of a variable into a command or script os that the instructions become dynamic and flexible instead of static. ex: ${var}

${var}

${var} is used in shell environments to insert the value of a variable into a command. var is the name of the variable we want to expand.

ex:

location="/var/log"

cd ${location}

Command Substitution

Command Substitution inserts the result of a command directly into another command or script.

'bar' - Single-Quoted String

Everything in the single quote is treated as literal text. There will be no variable expansion and no command substitution. The text will be printed as it is written.

ex:

echo 'Warning: $PATH cannot be found'

Warning: $PATH cannot be found

$(bar) - Substituting a Command

This is how command substitution is done. This will run the command inside the parentheses by replacing the $(...) with the command's output.

# /backup/YYYY-MM-DD
mkdir /backup/$(date +%F) # mkdir /backup/2025-11-15

Subshell Execution

A subshell is a separate child process created by the shell to execute a command or group of commands in isolation without affecting the current shell environment. What ever happens inside the subshell will not carry over to the main shell session.

(bar) - Creating a Subshell

The syntax is (cmd1; cmd2;...). All commands inside the parentheses are executed in a child shell.

ex:

# execute the command in a new shell
(bar)

Functions

A function is a set of commands packaged under a single name to allow repeated use without rewriting the commands each time.

ex:

function hello {
  echo "Hello, $1"
}

hello() {
  echo "Hello, $1"
}

Bash functions can only return numeric exit codes.

Variables by default are global. Use local to define a local variable in functions.

ex:

# to define a local variable in a function
function hello {
  local my_var="Hello"
}

Internal Field Separator / Output Field Separator

IFS tells the shell where to split input into distinct words.

OFS is a tool used to re-assemble data for output.

Avoiding Word Splitting

Word Splitting is the shell's habit of treating spaces, tabs, and newline inside a variable as natural break-point. To fix this, we wrap the variable in double quotes or pass it through printf. ex: printf '%s\n' "$variable".

With

file_path="My project/file.txt
cat file_path

the shell will attempt to open 2 files: My and project/file.txt.

But printf '%s\n' "$file_path" will produces the exact string, in one line, with no splits.

Controlling Input Splitting

IFS=<DELIMITER> read -r VAR1 VAR2,... <<< "$TEXT"

ex:

IFS=',' read -r name city role <<< "tome,New York,Developer"

Output Formatting

A common pattern is awk 'BEGIN{OFS="<DELIMITER>"} {print $1,$2,...}' <FILE>

ex:

# converting a portion of /etc/passwd file into a CSV
awk 'BEGIN{OFS=","} {print $1,$3,$4}' /etc/passwd | head -n 3

BEGIN{OFS=","} tells awk that commas should go between fields.

$1, $3, and $4 refers to the username, uid, and gid columns respectively.

Conditional Statements

if

It is used for running a single yes or no task like:

  • Verifying a service is running

  • Checking free disk space

  • Making sure a variable isn't empty

if condition; then
    commands
elif another_condition; then
    commands
else
    commands
fi
# to check for a file
location="/var/log/auth.log"

if [[ -f $location ]]; then
    echo "$location exists"
elif [[ -d $location ]]; then
    echo "$location is a directory"
else
    echo "$location does not exist"
fi

Options include:

  • -f for a file

  • -d for a directory

  • -z for a string

  • -eq numeric equal

  • -ne numeric not equal

  • -lt numeric less than

  • -gt numeric greater than

  • = string equal

  • != string not equal

case

A case statement is used when a variable can take several acceptable values, or answers, and needed different actions for each.

case expression in
    pattern1)
        commands ;;
    pattern2|pattern3)
        commands ;;
    *)
        commands ;;   # default case
esac
echo "Select an option: start | stop | restart"
read action

case $action in
    start)
        echo "Starting service..." ;;
    stop)
        echo "Stopping service..." ;;
    restart|reload)
        echo "Restarting service..." ;;
    *)
        echo "Unknown option: $action" ;;
esac

$1 is a positional parameter. It means it automatically holds the first command-line argument that was supplied when the script was launched.

Looping Statements

Loops allow a program to repeat actions automatically without rewriting the same instructions repeatedly.

for

for loop repeats a task a specific number of times of for each item in th a list.

ex:

for fruit in orange apple banana
  do
    echo "fruit: $fruit"
  done

while

while loop continues running as long as a condition remains true. A while loop is great when you do not know how many times something should repeat.

counter=1
while [ $counter -le 5 ]
  do
    echo "count is $counter"
    ((counter++))
  done

until

until runs until a condition becomes true.

counter=1
until [ $counter -ge 5 ]
  do
    echo "count is $counter"
    ((counter++))
  done

Interpreter Directive

An interpreter directive is a special line at the very top of the file that tells the system which program should be used to interpret the commands that follow.

It start with #! called shebang followed by the path of the interpreter like /bin/bash.

For bash script, we typically use #!/bin/bash

ex:

hello.sh

#!/bin/bash

echo "hello world"

Numerical Comparisons

  • -eq equal to

  • -ne not equal to

  • -lt less than

  • -le less than or equal to

  • -gt greater than

  • -ge greater than or equal to

They are always used in [] when making comparisons.

result=8
if [ "$result" -lt 5 ]; then
    echo "Less than 5"
elif [ "$result" -eq 5 ]; then
    echo "Equal to 5"
else
    echo "Greater than 5"
fi

Redirection String Operators

> redirection operator

> redirects outputs to a file. It creates the file automatically if it does not exist or overwrite its content if it exists.

echo "Operation completed with code 0" > result.txt

< redirection operator

< takes input from a file.

read value < input.txt

Comparison String Operators

'String comparison operators check whether two pieces of text are the same, different, match a pattern or follow a certain alphabetical order.

  • == and = for comparing if two strings are equal
  • != for checking if two strings are not equal
  • =~ for matching patterns using regular expressions
  • <= and >= for comparing string alphabetical order

==, =, and =~

== is typically used inside double square brackets ([[]]) and is read as is equal to.

= is used inside single square brackets ([]) and is read simply as equals.

=~ is used for more advanced comparison.

#!/bin/bash

text="Hello"

if [[$text == "Hello"]]; then
  echo "Text is exactly Hello"
fi

if [[$test =~ ^H]]; then
  echo "The test start with H"
fi

!=

#!/bin/bash

result="completed"

if [$result != "completed"]; then
  echo "The task completed successfully"
fi

<= and >=

This is a Lexicographical Comparison. Bash checks which string would come first or last in alphabetical order.

<= is read as is less than or equal to

>= is read as is greater than or equal to

#!/bin/bash

fruit="papaya"

if [[$fruit >= "mango"]]; then
  echo "$fruit comes after or is equal to mango"
fi

if [[$fruit <= "melon"]]; then
  echo "$fruit comes before or is equal to melon"
fi

Regular Expressions

A regex is a special sequence of characters that defines a search pattern.

Bash uses =~ inside [[]] to match patterns with regular expression ([[ $variable =~ pattern]]).

#!/bin/bash

data="234567"

if [[ $data =~ ^[0-9]+$ ]]; then
  echo "The data contains only numbers"
fi

Test Operators

Test operators are special symbols used to evaluate things like file existence, string content, and logical conditions. They return either true or false.

-d and -f

-d and -f are operators used in scripts to check whether something exists on the filesystem and whether it's is a directory or a regular file.

#!/bin/bash

if [ -d "project" ]; then
  echo "the project folder is a directory"
fi

if [ -f "app.conf" ]; then
  echo "app.conf is a file"
fi

-n and -z

-n and -z are string test operators. They help check whether a string has a value or is empty, which is especially useful when dealing with user input.

#!/bin/bash

input=""

if [ -z "$input" ]; then 
  echo "The input is empty"
fi

input="hello"

if [ -n "$input" ]; then
  echo "the input is not empty"
fi

!

! is the logical negation operator.

#!/bin/bash

if [ ! -f "config.txt" ]; then
  echo "config file does not exist"
fi

Variables

Variables are used to store and work with information like text, numbers, or user input.

Positional Arguments

Positional arguments are values passed to a script when running it, allowing the script to respond to user input. The first argument is $1, the second is $2 and so on.

#!/bin/bash

if [ $1 -gt 5 ]; then
  echo "The number is greater than 5"
else
  echo "The number is less than or equal to 5"
fi
# then run the script
./script.sh 10

Environment Variable

Environment variables are built-in variables provided by the system or user that store important information.

Built-in variables:

  • $USER: username
  • $HOME: home directory
  • $SHELL: current shell
#!/bin/bash

if [ $USER = 'root' ]; then
  echo "You are logged in as the root user"
else
  echo "You are logged as regular user $USER"
fi

Alias and Command Management

alias

alias command creates shortcuts for longer commands. The generic syntax is alias name='command'.

Aliases set in the terminal are only temporary and only last for that session.

# create a shortcut called ckdsk
alias ckdsk='df -h'

unalias

unalias command removes shortcuts that was previously created.

# to remove a previously created alias
unalias ckdsk

set

set modify the behavior of the shell.

#!/bin/bash
# to stop script from running if any command inside it fails
set -e

echo "running system update..."

sudo dnf update

echo "update completed"

Other options with set:

  • -x prints each command before it is executed
  • -u exits script when attempting to use an undefined variable
  • -o pipefail makes a pipeline fail if any command in the pipeline fails

Variable Management

  • export allows a variable to be passed to child processes
  • local restricts a variable's scope to within a function
  • unset deletes a variable

export

export is used to make a variable available to child processes, such as a subshell or another script that is launched from the current shell. The syntax is export VARIABLE=value

export LOG_LEVEL=debug

./myscript.sh # run in a separate shell process bt still has access to LOG_LEVEL because of 'export'

local

local command is used to restrict variable to within a function. The syntax is local VARIABLE=value

unset

unset is used to remove a variable. The syntax is unset VARIABLE

log_file="log.txt"

echo "processing file"

unset log_file

Return Codes

A return code or exit status is a number left behind after a command or program finishes in Linux to indicate success or failure.

$? is used to see the exit code of the last command.

  • 0 means success
  • Non-zero means error