Bash syntax
In this tutorial you will learn the basic syntax of Bash. This is also useful for other UNIX shells.
In the following examples we can use $
at the start to distinguish a command from its output.
Table of Contents
- Script structure
- exit
- Variables
- Working with text
- Arrays
- Operators
- Conditionals
- Curly braces: {}
- Loops
- Functions
- Bash parameters
- Script parameters
- Pipes / redirections
- Wildcards
Script structure
- It’s recommended to put in the first line the “shebang” (#!) followed by the location of the Shell interpreter you want to use.
#!/bin/bash
- In some systems,
bash
may be in other path, you can use this shebang for the system to find the right path:#!/usr/bin/env bash
.
- In some systems,
- Script files need to have execute permissions (and read permissions as well).
chmod +x script.sh
exit
exit
terminate the script. You can use it without parameters (same as exit 0
or not adding exit
) or you can add the exit status as a parameter.
exit 0
: means the program has terminated sucessfully.exit $?
: terminate with the exit status of the last command.exit <any positive number in the range [1..255]>
: program has terminated with an error (exit status<number>
). There are some reserved exit codes (https://tldp.org/LDP/abs/html/exitcodes.html) but you can define your own exit codes.
Variables
x=6
item="some text"
- Do not add spaces between
=
.
Reference a variable using $
and its name (or ${varname}
). You can type the variable inside double quotes (to prevent word splitting), but if you use single quotes, command will take the variable name as text.
$ item="some text"
$ echo $item
some text
$ echo ${item}
some text
$ echo "$item"
some text
$ echo '$item'
$item
You can echo
the output of a command (or do whatever you want with it) by using `COMMAND` or $(COMMAND)
.
$ echo date
date
$ echo `date`
vie 01 oct 2021 18:45:13 CEST
$ echo $(date)
vie 01 oct 2021 18:45:15 CEST
If you want to output a text with several lines, you can use echo -e
, printf
or use quotes.
y="One Line\nSecond Line"
printf $y
$ echo "hello
bye"
In some cases, you can also preserve newlines by referencing the variable like this: "${var}"
:
y=`cat file.csv`
echo "${y}"
echo "$(ls -l)"
Unset (delete) a variable with unset
.
unset y
Working with text
${var:start:character_number}
: select a substring of ‘var’ of ‘character_number’, starting from index ‘start’.$ a="text";echo ${a:0:2} te
$ a="text";echo ${a:1} ext
$ a="text";echo ${a::1} t
$ a="pass";echo ${a:(-1)} s
${var/pattern/replace}
: search ‘pattern’ in ‘var’ and replace with ‘replace’.# Replace first ocurrence $ a="text";echo ${a/t/r} rext
# Replace all ocurrences $ a="text";echo ${a//t/r} rexr
$ a="text";echo ${a/t} ext
- Modifying the case:
$ a="Hello World";echo ${a,,} hello world
$ a="Hello World";echo ${a^^} HELLO WORLD
Arrays
x=(3 5 9)
y=(some_word, "some sentence")
echo ${x[0]}
x[0]=6
echo ${x[0]}
$ ./script.sh
3
6
- You can wrap array references with double quotes
echo "${x[0]}"
- Print all items in an array.
echo ${x[@]}
- Print the number of items in an array.
echo ${#x[@]}
- Print array indexes
echo ${!x[@]}
Associative arrays
Arrays which indexes are strings. Always use declare -A
to declare an associative array.
declare -A arr
arr[test]=value
arr["some index"]="some value"
echo ${arr[test]}
You can also initialize an associative array in one line:
declare -A arr2=([i1]=v1 [i2]=v2)
Operators
Arithmetic
+ - * /
%
: modulus (remainder of a division).**
: power operator.x++
: increasex
by one.
Use $
and double parenthesis to do calculations:
$ echo $((5 + 8))
13
$ calc="2*3";echo $(($calc))
6
# time shell has been runing
$ echo "$(($SECONDS / 60)) minutes"
87 minutes
Because using $
with variables in arithmetic operations is optional, you can also do:
echo "$((SECONDS / 60)) minutes"
or
calc="2*3";echo $((calc))
Bolean
- Strings:
= == != -z #test if a string is null -n #test if a string is not null
- Files:
-e #test if a file exists -f #test if a file is a regular file -d #test if a file is a directory -L #test if a file is a symbolic link
- Numbers (if you use
[ ]
to enclose the condition):-eq
: equal to.-gt
: greater than.-ge
: greater than or equal to.-lt
: less than.-le
: less than or equal to.-ne
: not equal to.
Conditionals
if, elif, else
Basic structure:
if [ EXPRESSION ]
then COMMAND
else COMMAND
fi
EXPRESSION
is usually enclosed in brackets[ ]
, but you can use a command (the first bracket[
is a shortcut for thetest
command).if [ $x -eq 6 ]
if test $x -eq 6
- If you add
then
in the same line asif
, you must use a semicolon.if [ $x -eq 6 ];then
if [ $x -eq 6 ]
then echo "x is equal to 6"
else echo "x is not equal to 6"
fi
# or
if [ $x -eq 6 ]
then
echo "x is equal to 6"
else
echo "x is not equal to 6"
fi
# or
if (($x == 6))
then
echo "x is equal to 6
else
echo "x is not equal to 6"
fi
if [ $y = "house" ]
then
echo "y is equal to house"
elif [ $y = "office" ]
then
echo "y is equal to office"
else
echo "y is not equal to house or office"
fi
You can also use this structure for simple conditionals:
[ $x -eq 6 ] && echo "x is equal to 6" || echo "x is not equal to 6"
$ [ -e lectura-agua.csv ] && echo "OK" || echo "FALSE"
OK
Use double brackets ([[ ]]
) when you need to use the AND (&&
) and OR (||
) operators inside the condition.
if [[ $x -gt 6 && $x -lt 9 ]]
then
echo "x is greater than 6 but less than 9
fi
Note that you need to add spaces between the operator in all cases.
Curly braces: {}
You can use {}
to build an array or a range, to expanse a parameter or to group command outputs.
$ echo {1..5}
1 2 3 4 5
$ touch ABC_{1..20}.txt
$ ls
ABC_10.txt ABC_12.txt ABC_14.txt ABC_16.txt ABC_18.txt
ABC_1.txt ABC_2.txt ABC_4.txt ABC_6.txt ABC_8.txt
ABC_11.txt ABC_13.txt ABC_15.txt ABC_17.txt ABC_19.txt
ABC_20.txt ABC_3.txt ABC_5.txt ABC_7.txt ABC_9.txt
$ mkdir 202{0..3}-{01..12}
$ ls
2020-01 2020-05 2020-09 2021-01 2021-05 2021-09 2022-01 2022-05 2022-09 2023-01 2023-05 2023-09
2020-02 2020-06 2020-10 2021-02 2021-06 2021-10 2022-02 2022-06 2022-10 2023-02 2023-06 2023-10
2020-03 2020-07 2020-11 2021-03 2021-07 2021-11 2022-03 2022-07 2022-11 2023-03 2023-07 2023-11
2020-04 2020-08 2020-12 2021-04 2021-08 2021-12 2022-04 2022-08 2022-12 2023-04 2023-08 2023-12
# expands to 'mv image.jpeg image.jpg'
$ mv image.{jpeg,jpg}
$ echo {0..6..2}
0 2 4 6
Loops
for
for i in $some_array
do
echo $i
done
for i in {1..30}
do
[ if $i = 15 ]
then break
# this will stop the loop, use 'continue' instead of 'break' to jump to the next loop item
fi
echo $i
done
for i in *.pdf
do
echo $i
done
while
i=5
while [ $i -gt 0 ]
do
echo $i
i=$((i - 1))
done
awk '{print $1, $3}' somefile | while read n1 n2
do echo "N1 is equal to $n1 and N2 is equal to $n2"
done
case
case $x in
3) echo "x is equal to 3";;
6) echo "x is equal to 6";;
*) echo "x is not equal to 3 or 6";;
esac
case $1 in
"") echo "No parameters"
exit 1;;
some_parameter) echo $1;;
*) echo "Parameter is not 'some parameter'
exit 1;;
esac
select
PS3="Select the item: "
select item in "i1" "i2" "i3"
do echo "You've selected $item"
break
done
Functions
Definition
Function definition must precede invocation.
function_name(){
command1
command2
}
# In one line, remember to add a semicolon after each command
function_name() { command1; command2; }
Invocation
function_name
Function arguments
You can pass arguments to functions.
fun(){
if [ -n $1 ]
then
echo $1
fi
}
fun arg1
To pass an script argument to a function, you must invocate the function with that argument.
# ./script.sh arg1
fun(){
if [ -z $1 ]
then
echo "No argument passed."
else
echo $1
fi
}
fun $1
Bash parameters
-n
: test the syntax of a script without having to execute it.bash -n ./script.sh
-x
: turn on debugging.
Script parameters
./script.sh arg1 arg2
- You can access these arguments using
$
and1
for the first argument,2
for the second, etc.#!/bin/bash if [ -n $1 ] then first_argument=$1 echo $first_argument fi
$ ./script.sh my_argument my_argument
Some characters have special meanings (referring to parameters):
$#
: number of parameters.$@
or$*
: a list with the parameters.$0
: displays the script path (relative or absolute).
There are several ways to loop between the parameters:
while [ $# -gt 0 ];do
case $1 in
-e) echo "Found 'e' parameter";;
-config) echo "Found 'config' parameter"
CONFVALUE=$2
shift #Delete first argument and move the second to first place, third to second place, etc.
if [ $CONFVALUE -gt 10 ];then
echo "Error: Config value must be less than 10"
exit 1
fi
;;
esac
shift
done
for arg in $@; do
case $arg in
-a) echo "Found 'a' parameter";;
-b) echo "Found 'b' parameter;;
*) echo "Unknown parameter;exit 1;;
esac
done
Pipes / redirections
command1 | command2
: transform the output fromcommand1
into the input ofcommand2
.cat /etc/passwd | grep root
- You can specify where to add the output of the first command by using
-
in the second command.
- You can specify where to add the output of the first command by using
command > file
: create (or overwrite) a file with the output fromcommand
find . -maxdepth 1 > files.txt
command >> file
: append the output fromcommand
intofile
(in a new line). It does not overwrite the file if it exists but it will create it if it does not exist.command < file
: use the content offile
as input tocommand
.command 2>file
: redirect standard error fromcommand
tofile
.# Redirect stdout and stderr to same location ls /somefolder > file.txt 2>&1 # this is the same as: ls /somefolder &> file.txt
for i in {0..20}; do ls test_$i.txt 1>/dev/null; done
- Show only the files that do not exist in that range (
1
refers to standard output,2
to standard error).
- Show only the files that do not exist in that range (
command << EOF
: this is called a ‘here document’ and allows to pass multiline text to a command.EOF
could be any word you can use to define the end of the text.$ cat > multiline.txt << EOF > one > two > three > EOF
command <<< text
: you can use ‘here strings’ to feed a command with some text.awk '{print $2}' <<< "Some text"
Wildcards
*
: matches any number of characters.ls *.png
?
: matches a single character.ls 202201??.png
[]
: matches any one of the enclosed characters.ls 202[23]_report.pdf
{}
: matches a range.ls file_{1..20}.txt
If you have any suggestion, feel free to contact me via social media or email.
Latest tutorials and articles:
Featured content: