Control flow
Loops and conditionals allow to change the flow of execution.
For loops
To apply a set of commands to all the elements of a list, you can use a for loop.
Syntax
The general structure of a for loop is as follows:
for <iterable> in <list>
do
<command1>
<command2>
...
done
Example
The molecules
directory contains the following .pdb
files:
ls *.pdb
cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb
We want to rename these files by prepending “gas_” to their current names.
Wildcards don’t work here:
mv *.pdb gas_*.pdb
mv: target 'gas_*.pdb': No such file or directory
The solution is to use a for loop:
for file in *.pdb
do
mv $file gas_$file
done
This can also be written as a one-liner, although it is harder to read:
for file in *.pdb; do mv $file gas_$file; done
Your turn:
Using what we learnt in the string manipulation section, how could you remove the gas_
prefix to all these files?
Collections
For loops run a set of commands for each item of a collection. How do you create those collections?
Listing items one by one
The least efficient method is to list all the items one by one:
Example:
for i in file1 file2 file3
do
echo $i
done
file1
file2
file3
Wildcards
As we have already seen, wildcards are very useful to build for loops.
Brace expansion
Collections can also be created with brace expansion.
Examples:
echo {1,2,5}
1 2 5
Make sure not to add a space after the commas.
echo {list,of,strings}
list of strings
echo {file1,file2}.sh
file1.sh file2.sh
ls -l {ethane,methane,pentane}.pdb
-rw-rw-r-- 1 marie marie 622 Sep 16 2021 ethane.pdb
-rw-rw-r-- 1 marie marie 422 Sep 16 2021 methane.pdb
-rw-rw-r-- 1 marie marie 1226 Sep 16 2021 pentane.pdb
echo {1..5}
1 2 3 4 5
echo {01..10}
01 02 03 04 05 06 07 08 09 10
echo {r..v}
r s t u v
echo {v..r}
v u t s r
echo {a..e}{1..3}
a1 a2 a3 b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3
echo {a..c}{a..c}
aa ab ac ba bb bc ca cb cc
echo {1..5}.txt
1.txt 2.txt 3.txt 4.txt 5.txt
echo file{3..6}.sh
file3.sh file4.sh file5.sh file6.sh
Brace expansion can be used to create lists iterated over in loops, but also to apply commands to files or directories.
Sequences
Collections can also be sequences:
seq 1 2 10
1
3
5
7
9
Here, 1
is the start of the sequence, 10
is the end, and 2
is the step.
Such a sequence could be used in a loop this way:
for i in $(seq 1 2 10)
do
echo file$i.txt
done
file1.txt
file3.txt
file5.txt
file7.txt
file9.txt
Your turn:
In a directory the command ls
returns:
fructose.dat glucose.dat sucrose.dat maltose.txt
What would be the output of the following loop?
for datafile in *.dat
do
cat $datafile >> sugar.dat
done
All of the text from
fructose.dat
,glucose.dat
andsucrose.dat
would be concatenated and saved to a file calledsugar.dat
.The text from
sucrose.dat
will be saved to a file calledsugar.dat
.All of the text from
fructose.dat
,glucose.dat
,sucrose.dat
, andmaltose.txt
would be concatenated and saved to a file calledsugar.dat
.All of the text from
fructose.dat
,glucose.dat
andsucrose.dat
will be printed to the screen and saved into a file calledsugar.dat
.
While loops
Syntax
The syntax of a while loop in Bash is:
while predicate
do
command1
command2
...
done
The set of commands in the body of the while loop are executed as long as the predicate returns true.
Be careful that while loop can lead to infinite loops. Such loops need to be manually interrupted (by pressing <Ctrl+C>
).
Example of infinite loop:
while true
do
echo "Press <Ctrl+C> to stop"
sleep 1
done
Here is a video of a previous version of this workshop.
Conditionals
Syntax
if [ predicate1 ]
then
command1
command2
...
elif [ predicate2 ]
then
command3
command4
...
else
command5
command6
...
fi
Example
Let’s create a file called check.sh
with the following if statement:
for f in $@
do
if [ -e $f ] # Make sure to have spaces around each bracket
then
echo $f exists
else
echo $f does not exist
fi
done
Now, let’s make it executable:
chmod u+x check.sh
And let’s run this:
./check.sh file1 file2 check.sh file3
Predicates
Here are a few predicates:
[ $var == 'text' ]
checks whether var
is equal to 'text'
.
[ $var == number ]
checks whether var
is equal to number
.
[ -e file ]
checks whether file
exists.
[ -d name ]
checks whether name
is a directory.
[ -f name ]
checks whether name
is a file.