2.Comments
3.Arrays
6.Loops
Variable declaration is super easy, the only caveat is that should not contains spaces between the varaible name and the value
foo='bar'
foo = 'bar'
foo= 'bar'
foo ='bar'
Or you can use ""
foo="bar"
If it's just a single word it's not required to use '' or ""
foo=bar
When use '' ""
''
its used for exact match but""
its used for string interpolation
message='world'
echo "Hello $message"
#Output: Hello world
echo 'Hello $message'
#Output: Hello $message
Bash dosen't diferentiate between true
or false
so if you declare a variable with this value it's treated as a string.In the others sections you'll gonna learn how to do
Conditionals
foo=bar
echo ${foo}
echo $foo
echo "$foo"
echo '$foo' # Exact string => '$foo'
echo "${foo} !" # => bar !
# This is a comment
: '
Multine comment
You can cooment here to
'
Arrays in bash are dynamic.For declare one you only need to put the elemenets inside a ()
because this is a constructor.The spaces are interpreted as separators don't use ,
for that.
elements=('foo' 'bar')
boys=('foo' 'bar' 2025)
If you try to use $array[index]
can cause unexpeted behavior becouse $array[index]
access to the first argument.
val=(21 'foo' 'bar')
echo $val[0]
# Output: 21[0]
# Look at this weird behavior
echo $val[2]
# Output: 21[2]
Working with arrays and strings should be the same deal becouse a string it's just an array of characters but not.Bash take a diffrent aproach you should olways specify the start and end position ${STR:position:length}
if the length it's ommited it's gonna take the rest of the string.
foo='bar'
echo "${foo:0}"
#Output: bar
foo='bar'
echo "${foo:0:1}"
#Output: b
names=('mark' 'anthony')
echo ${name[0]}
# Output: mark
#String example
foo='bar'
echo "${foo:0:1}"
#Output: b
names=('mark' 'anthony')
echo ${name[-1]}
# Output: anthony
foo='bar'
echo ${foo: -1} #The space it's requiered
#Output: r
You should put an space between :
and -1
because bash interprete this as an expansion parameter for asign a default value if foo
it's not defined.
echo ${foo:-default}
#Output: default
names=('mark' 'anthony')
echo ${name[@]}
# Output: mark anthony
# Or you can use the alternative syntax
echo ${name[*]}
# Output: mark anthony
# For an string
foo='bar'
echo $foo
names=('mark' 'anthony')
echo ${#names[*]}
# Output: 2
name='amrk'
echo ${#name}
#Output: 4
names=("mark" "anthony")
echo ${#names}
# Output: 4
names=("mark" "anthony")
echo ${#names[1]}
# Output: 7
names=("mark" "anthony" "george")
echo ${names[*]:1:2}
# Output: anthony george
# In strings
name='fooz'
echo ${name:1:2}
#Output: oo
${!names[*]}
names=("mark" "anthony" "george")
for i in ${!names[*]}; do
echo $i
done
# Output:
# 0
# 1
# 2
#For strings
message='hello world'
length=${#message}
for ((i = 0; i < length;i++));do
echo ${message:i:1}
done
#Output:
# h
# e
# l
# l
# o
# w
# o
# r
# l
# d
#Short syntax
message='hello world'
for ((i = 0; i < ${#message};i++));do
echo ${message:i:1}
done
names=("mark" "anthony" "george")
names+=("marian")
echo ${names[*]}
# Output: mark anthony george marian
# In strings
foo='bar'
foo+="-more-text"
echo $foo
#Output: bar-more-text
names=("mark" "anthony" "george")
names+=("marian" 22 "user")
echo ${names[*]}
# Output: mark anthony george marian 22 user
names=("mark" "anthony" "george")
names+=("marian")
unset names[0]
echo ${names[*]}
# Output: anthony george marian
Conditions are expresions that returns 0 or 1 in Unix systems, you should interprate this like true
or false
.Bash do not evaluate conditional expresions like other programming lenguages.Intead it's check the status code of the commands.
0 means true/successs
Non-cero (1-255) means false/failure
For see the practical examples you'll gonna use the if
flow that allows conditional execution of commands.
if COMMAND_OUTPUT ; then
# expresions or commands
fi
#or
if COMMAND_OUTPUT ; then
# expresions or commands
elif COMMAND_OUTPUT;then ...
elif COMMAND_OUTPUT;then ...
fi
[ ]
is actually an alias for thetest
command[[ ]]
is a bash keyword with more features like regular expresions,etc;
if [ 1 -eq 1 ];then
echo "valid condition"
fi
# Output: valid condition
var="~/.config/nvim/init.lua"
if [[ $var == *.lua ]];then
echo "it's a lua file"
fi
if ping -c 1 googe.com; then
echo "google service it's running"
else
echo "google it's not available"
fi
Bash allow you multiple commands into the same condition
if condition1 && condition2;then ...
if condition1 || condition2;then ...
-
[[]]
it's generally more faster that[]
becouse it's builtin. -
[]
can fail if variable it's empty or have white spaces.
if [ $input == "text input" ];then
echo "hello world"
fi
#Output: ./test.sh: line 3: [text: command not found
Empty variable
input=""
if [ $input == "text input" ];then
echo "hello world"
fi
#Output: ./test.sh: line 3: [: missing `]'
- More intuitive logical operators,
[[]]
allows&&
and||
directly.[]
requires-a
for&&
and-o
for||
.
- For compatibility with
sh
- Some embeded systems
- [[ NUM1 -eq NUM2 ]] Equal
- [[ NUM1 -ne NUM2 ]] Not equal
- [[ NUM1 -lt NUM2 ]] Less than
- [[ NUM1 -le NUM2 ]] Less than or equal
- [[ NUM1 -gt NUM2 ]] Greater than
- [[ NUM1 -ge NUM2 ]] Greater than or equal
- (( NUM1 != NUM2 )) Not equal
- (( NUM1 == NUM2 )) Equal
- (( NUM1 < NUM2 )) Less than
- (( NUM1 <= NUM2 )) Less than or equal
- (( NUM1 > NUM2 )) Greater than
- (( NUM1 >= NUM2 )) Greater than or equal
input1=1
input2=3
if [[ input1 -lt input2 ]];then
echo "first number is less"
fi
For arithmetic expresion it's more recomended to use (())
becouse:
- It's more easy to work with.
- Allows variable assignacion
(( x = 5 ))
- More operands
++, --, +=, -=
input1=1
if (( input1 == 1 ));then
echo "Equal"
fi
- [[ -z STR ]] The string is empty
- [[ -n STR ]] The string is not empty
- [[ STR1 == STR2 ]] Equal
- [[ STR1 != STR2 ]] Not equal
- [[ STR1 < STR2 ]] Less than(ASCII)
- [[ STR1 > STR2 ]] Greater than(ASCII)
- [[ STR1 =~ STR2 ]] Regex
name="foo"
if [[ -z "$name" ]];then
echo "the string it's empty"
elif [[ -n "$name" ]];then
echo "the string its not empty $name"
else
echo "this don't gonna happend"
fi
Why use the $variable
surronded with ""
becouse if the string have more than one word it's gonna lead unexpeted behaviors.
num1=1
num2=2
name="foo"
if (( num1 == 1 )) && (( num2 == 2 )) &&
[[ -n "$name" && ${#name} -eq 3 ]];then
echo "valid condition"
fi
In bash there is not a switch
structure like others programming lengiages but you can archive the same result with case
case $VAR in
pattern )
# Some comands or definitions
;; # End of the pattern
pattern1 | pattern2) # Or operator
...
;;
*)
# Default command
;;
esac
num=1
case $num in
1 )
echo "the number is one"
;;
2 | 10)
echo "it's in range 2-10"
;;
*)
echo "unknow number"
;;
esac
cfg_file='config.json'
case $cfg_file in
*.json)
echo "configuration file"
;;
*.png|*.jpeg|*.jpg)
echo "image file"
;;
*)
echo "unknow file type"
;;
esac
#Output: configuration file
for i in ~/.config/*;do
echo $i
done
# Output: print all the content of the directory
for ((i = 0; i < 100;i++));do
echo $i
done
# Output:
# 0
# 1
# ...
# 99
for i in {2..6};do
echo $i
done
# Output:
# 2
# 3
# 4
# 5
# 6
i=0
while (( i < 100 ));do
echo $i
(( i ++ ))
done
# Output:
# 0
# 1
# ...
# 99
i=100
while (( i >= 0 ));do
echo $i
(( i -- ))
done
# Output:
# 100
# 99
# ...
# 1
# 0
for (( i = 0; i < 100;i++));do
if (( i >= 20 && i <= 50 ));then
continue;
fi
if (( i == 90 ));then
break;
fi
echo "valid range $i"
done
#Output:
# 0
# 1
# ...
# 19
# 51
# ...
# 88
# 89
while true;do
echo "forever"
done
# Shorthand
while :;do
echo "forever"
done
You can access to the arguments of your program just like variable declaration but with the position of the argument
./script.sh foo bar steve
echo $1 $2 $3
# foo bar steve
# The argument $0 is the name of the script
echo $0
# ./script.sh
./script.sh foo bar
echo $#
# It's gonna print 2
./script.sh foo bar
echo $$
# It's gonna print some number Example: 2711
./script.sh foo bar
echo $*
# foo bar
./script.sh foo bar
echo $@
# foo bar
Functions are way to reuse code in your programs.If the program become larger using functions is a way to tackle the complexity.
my_func() {
}
When you declare a variable in a function with out the keyworl local the variable become available to the rest of the script and can cause unexpected behaviors and name collisions.
func () {
i=100
}
func # this is how you made a function call
func args1 arg2 # Arguments
echo $i
#Output: 100
Functions arguments works the same as program arguments except for $0
that access to the name of the script
func () {
local i=100
echo $1
}
func 'user'
#Output: user
Program options change the default behavior of some funtions in bash this should be defined at the begging of the program.
# Used to exit upon errors, avoiding cascading errors
set -o errexit
# Unveils hidden failures
set -o pipefail
# Expose unset variavles
set -o nounset
#No matching glog are removed
# '*.foo' => ''
set -o nullglob
# Allow ** for recursive matches
set -o globstart