Bash Basics

Bash is a commonly used language on most Linux System. The name Bash stands for ‘Bourne Again SHell’. It is developed as a replacement/improvement for Bourne Shell(sh).

Installation

To install or update bash in MacOS using Homebrew

1
brew install bash

Hello World

1
2
3
4
#!/bin/bash

echo "Hello Bash" # prints 'Hello Bash'
exit 0

Script Execution

Bash script file is a text file with commands. To execute the bash script, first make the file executable

1
chmod +x myscript

Then you can run the script by prefixing it with ./. This tells Bash to look for the script in current directory. by default Bash only executes commands in $PATH.

1
./myscript

An alternative way is to use bash command. But the problem for this approach is that you can’t provide arguments to the script.

1
bash myscript

You can also add the script to system path so that it can be executed in any path. A common place to store the script is /usr/local/bin.

Shebang

#!/bin/bash is not a comment, it is a Shebang. Shebang should be the first line in a bash file. Shebang tells Bash how to do the interpretation. /bin/bash is the path to the interpreter that is used.

Print Output to Terminal

echo command is the most used command to print output to the terminal

1
echo 'hello world'

output

1
hello world

Variable

Like other script languages, you can define variable in Bash. You use assign operator = to assign value to a variable. Note that you can’t have space before and after = sign.

1
2
3
var0=Hello
var1="World"
var2=$var1

This is Invalid because var0 follows a space. Bash will inteprete var0 as a command

1
2
$ var0 = 2
var0: command not found

To reference a variable, you prefix a variable with a dollar sign. ‘$’ character here is used for parameter expansion.

1
echo $var2

In a string defined by a double quote, the variables are also referenced. This doesn’t work for string defined by single quote.

1
echo "$var0 $var1!"

will print

1
Hello World!

Parameter Expansion

The ‘$’ character introduces parameter expansion.

The basic form of parameter expansion is ${parameter}. The braces are optional. It is used so that the characters following the variable will not be misinterpreted as part of a parameter.

Ther are many forms of parameter expansion. You can use it to get parameter length, get substring or do substitution.

Getting User Input

use read command to read input from user. if input contains backslash, add -r option. see Bash Guide for Beginners - Catching user input

1
2
3
4
read -p "username: " username
read -sp "password: " password
echo $username
echo $password

Command Substitution

Command Substitution allows user to execute a command and replace the text of the command with the output of the command.

Syntax - recommended is $(). Backquote is not recommended.

1
$(command)

or

1
`command`

example - create file with date postfix

1
touch file-$(date +%y-%m-%d).txt

exmaple - generate uuid

1
2
uuid=$(uuidgen)
echo "generated uuid: $uuid"

Pass Arguments to Bash Script

You can pass parameter to bash script. use $1, $2 to access them. $0 is the name of the Bash script

Here is a file hello.sh

1
2
#! /bin/bash
echo $0 $1 $2 $3

If you run ./hello.sh Alice Bob Cathy. The output will be

1
./hello.sh Alice Bob Cathy

You can assign the arguments to an array. Note that the first element of the array is the first argument not the name of the Bash script.

1
2
args=("$@")
echo ${args[0]} ${args[1]} ${args[2]}

You can get the number of arguments using $#

1
echo $#

Exit Code

exit 0 is for normal exit of the application. scripts should return non-zero value if it fails. You can use echo $? to check the exit status.

1
echo $?

Ignore the error

Sometimes you want to ignore an error and continue the execution. To do that, just add || antohercommand to the end.

1
command || true

Math Calculation

1
var1=$(( 1 + 2 ))

Conditional Statements

If Statement

1
2
3
if command; then
<commands>
fi

Here semicolon is needed. it is used to separate commands. You will get a syntax error if you don’t have it.

In the if statement, square brackets([]) is often used to test condition. square bracket use command test to evaluate the expression. see test online man page for test command usage.

test command parameter description
! expr the expr is false
-n STRING the length of STRING is nonzero
STRING equivalent to -n STRING
-z STRING the length of STRING is zero
STRING1 = STRING2 the strings are equal
STRING1 != STRING2 the strings are not equal
INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2
INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2
INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2
file test command description
-e FILE FILE exists
-f FILE FILE exists and is a regular file
-d FILE FILE exists and is a directory

Sometimes double square([[) bracket is used to test condition. unlike [, which is a POSIX shell command, [[ is a bash keyword. [[ is supported by bash and other shells(zsh, ksh). Parsing rules for keywords makes conditions written by [[ easier to understand.

if… satement example

If parameter is not provided, print the usage message

1
2
3
if [ -z $1 ]; then
echo "usage - test.sh val1"
fi

if variable a is greate than b, then print ‘a > b’

1
2
3
if [ $a -gt $b ]; then
echo 'a > b'
fi

Check if file exists and is a regular file.

1
2
3
4
if [ -f $1 ]
then
echo "$1 exists"
fi

if…else… statement example

1
2
3
4
5
6
if ! [ -z $1 ]
then
echo "value 1 = $1"
else
echo "usage - test.sh val1"
fi

print parameter. If parameter is not provided, print the usage message.

if…elif…else statement

1
2
3
4
5
6
7
if [ -d $1 ]; then
echo "$1 is a directory"
elif [ -f $1 ]; then
echo "$1 is a file"
else
echo $1 is not a file, nor a directory
fi

Case Statement

1
2
3
4
5
6
7
8
case <variable> in
<pattern 1>)
<commands>
;;
<pattern 2>)
<other commands>
;;
esac

case statement example

1
2
3
4
5
6
7
8
9
10
11
12
system=$(uname)
case $system in
Linux)
echo 'You are a Linux user!'
;;
Darwin)
echo 'You are a Mac user!'
;;
*)
echo 'You are using other machine!'
;;
esac

It will print a massage base on the system the user is in.

Loops

While

While Syntax, you can use break and continue in the while body.

1
2
3
4
while [ <some test> ]
do
<commands>
done

while example - print 0 - 4

1
2
3
4
5
6
count=0
while [ $count -lt 5 ]
do
echo $count
count=$(( count + 1))
done

while example - read lines from file

1
2
3
while read line; do
echo $line
done < input.txt

break example

1
2
3
4
5
6
while read line; do
if [[ "$line" =~ "########" ]]; then
break
fi
echo "$line"
done < $input

continue example

1
2
3
4
5
6
7
input="/etc/hosts"
while read line; do
if [[ "$line" =~ ""########"" ]]; then
continue
fi
echo "$line"
done < $input

For

1
2
3
4
for var in <list>
do
<commands>
done

Example - process regular text files in the current folder

1
2
3
4
5
6
7
8
curFiles="./*"
for file in $curFiles
do
if [ -f $file ] && [[ "$file" == *.txt ]]
then
echo "processing $file"
fi
done

Function

Unlike functions in other programming language, bash function do not return anything to the caller. To return value, you use global variable to store the value.

To define and call a function

1
2
3
4
5
function printSeparater {
echo "========================="
}

printSeparater

Or you can define it like this

1
2
3
4
5
printSeparater() {
echo "========================="
}

printSeparater

parameters can be access using $1, $2

1
2
3
4
5
printtitle() {
echo "==================== $1 ======================="
}

printtitle 'my title'

Resources and Tutorials

Reference