mv *.pdb gas_*.pdb
mv: target 'gas_propane.pdb': Not a directory
Marie-Hélène Burle
By default, scripts get executed linearly from top to bottom. Often however, you will want to control what gets executed when.
This section will cover various ways to control the flow of execution through a script.
For this section, we will play with files created by The Carpentries.
You can download them into a zip file called bash.zip
with:
You can then unzip that file with:
You should now have a data-shell
directory with a molecules
subdirectory.
cd
into it:
Commands can be limited to running only if the previous commands ran successfully thanks to &&
.
Example:
Look at the following commands:
This is equivalent to:
and to:
This is what we did to get the data for the past few sessions.
In both cases, both commands will try to run. Now, if for some reason, the unzipping fails, we have deleted the zip file and we have to re-download it. Not a big deal here, but in some situations, executing a command if the one before fails can be a real bummer.
To prevent this, we can use the double-ampersand (&&
) operator:
This is equivalent to:
If the unzipping works (if it returns a zero exit status), then the Zip file gets deleted. If however, the unzipping fails (if it returns a non-zero exit status), the script aborts and we haven’t lost our Zip file.
Sections of scripts can be repeated for each element of a list thanks to for loops.
The general structure of a for loop is as follows:
The molecules
directory contains the following .pdb
files:
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:
The solution is to use a for loop:
This can also be written as a one-liner, although it is harder to read:
Your turn:
Using what we learnt in the string manipulation section, how could you remove the gas_
prefix to all these files?
For loops run a set of commands for each item of a collection. How do you create those collections?
The least efficient method is to list all the items one by one:
Example:
file1
file2
file3
As we have already seen, wildcards are very useful to build for loops.
Collections can also be created with brace expansion.
Examples:
Make sure not to add a space after the commas.
ls: cannot access 'ethane.pdb': No such file or directory
ls: cannot access 'methane.pdb': No such file or directory
ls: cannot access 'pentane.pdb': No such file or directory
Brace expansion can be used to create lists iterated over in loops, but also to apply commands to files or directories.
Collections can also be sequences:
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:
Your turn:
In a directory the command ls
returns:
What would be the output of the following loop?
All of the text from fructose.dat
, glucose.dat
and sucrose.dat
would be concatenated and saved to a file called sugar.dat
.
The text from sucrose.dat
will be saved to a file called sugar.dat
.
All of the text from fructose.dat
, glucose.dat
, sucrose.dat
, and maltose.txt
would be concatenated and saved to a file called sugar.dat
.
All of the text from fructose.dat
, glucose.dat
and sucrose.dat
will be printed to the screen and saved into a file called sugar.dat
.
Sections of scripts can be repeated as long as a condition returns True
thanks to while loops.
The syntax of a while loop in Bash is:
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:
Here is a video of a previous version of this workshop.
Sections of scripts can be executed (or not) based on conditions thanks to if statements.
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:
And let’s run this:
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.