variable=This string is the value of the variable
echo $variable
bash: line 1: string: command not found
Marie-Hélène Burle
This workshop will demystify the command line and get you started using Bash and Bash scripting.
Warning: you might find that working in the command line is actually really fun and addictive!
A Unix shell is a command line interpreter: the user enters commands as text, either interactively in the command line or in a script, and the shell passes them to the operating system.
Bash (Bourne Again SHell), released in 1989, is part of the GNU Project and is the default Unix shell on many systems (MacOS recently changed its default to zsh).
Prior to Bash, the default was the Bourne shell (sh).
A new and popular shell (backward compatible with Bash) is zsh. It extends Bash’s capabilities.
Another shell in the same family is the KornShell (ksh).
All these shells are quite similar. The C shell (csh) however was modeled on the C programming language.
Bash is the most common shell and the one which makes the most sense to learn as a first Unix shell.
While automating GUI operations is really difficult, it is easy to rerun a script (a file with a number of commands). Unix shells thus allow the creation of reproducible workflows and the automation of repetitive tasks.
They are powerful to launch tools, modify files, search text, or combine commands.
They also allow to work on remote machines and HPC systems.
Bash is a Unix shell. You thus need a Unix or Unix-like operating system.
We will connect to a remote HPC system via SSH (secure shell). HPC systems always run Linux.
Those on Linux or MacOS can alternatively use Bash directly on their machine. On MacOS, the default is now zsh (you can see that by typing echo $SHELL
in Terminal), but zsh is fully compatible with Bash commands, so it is totally fine to use it instead. If you really want to use Bash, simply launch it by typing in Terminal: bash
.
We will give you a link to an etherpad during the workshop. Add your name next to a free username to claim it.
We will also give you the password for our training cluster. When prompted, enter it.
Note that you will not see any character as you type the password: this is called blind typing and is a Linux safety feature. Type slowly and make sure not to make typos. It can be unsettling at first not to get any feed-back while typing.
Linux users: open the terminal emulator of your choice.
MacOS users: open “Terminal”.
Then type:
We suggest using the free version of MobaXterm.
MobaXterm comes with a terminal emulator and a GUI interface for SSH sessions.
Open MobaXterm, click on “Session”, then “SSH”, and fill in the Remote host name and your username. Here is a live demo.
In command-line interfaces, a command prompt is a sequence of characters indicating that the interpreter is ready to accept input. It can also provide some information (e.g. time, error types, username and hostname, etc.)
The Bash prompt is customizable. By default, it often gives the username and the hostname, and it typically ends with $
.
Man pages:
Man pages open in a pager (usually less
).
Navigate up/down with the space bar and the b
key.
Quit the pager with the q
key.
Help pages:
Inspect commands:
pwd
cd
echo
cat
ls
cp
mv
mkdir
touch
Clear the terminal (command clear
) with C-l (this means: press the Ctrl and L keys at the same time).
Navigate command history with C-p and C-n (or up and down arrows).
You can auto-complete commands by pressing the tab key.
Instead of typing commands one at a time directly in a terminal, you can write them down, one per line, in a text file called a script.
They will be run in the order in which they are written when you execute the script.
This is a great way to automate tasks: to rerun this sequence of commands, you simply have to rerun the script.
Shell scripts, including Bash scripts, are usually given the extension sh
(e.g. my_script.sh
).
You can store scripts anywhere, but a common practice is to store them in a ~/bin
directory.
Scripts can be written for any interpreter (e.g. Bash, Python, R, etc.) The way to tell the system which one to use is to use a shebang (#!
) followed by the path of the interpreter on the first line of the script.
To use Bash, start your scripts with:
You may also encounter this notation:
If you are curious, you can read the answers to this Stack Overflow question for the differences between the two.
There are two ways to execute a script:
In the latter case, you need to make sure that your script is executable by first running:
Open a text editor (e.g. nano) and type:
Save and close the file.
Your turn:
Now run the script with one, then the other method.
What does this script do?
You can declare a variable (i.e. a name that holds a value) with the =
sign.
!! Make sure not to put spaces around the equal sign.
Let’s experiment with quotes:
bash: line 1: string: command not found
Oops…
This string is the value of the variable
This string is the value of the variable
bash: -c: line 1: unexpected EOF while looking for matching `''
Oops…
One solution to this is to use double quotes:
This string's the value of the variable
Alternatively, single quotes can be escaped:
This string's the value of the variable
Admittedly, this last one is a little crazy. It is the way to escape single quotes in single-quoted strings.
The first '
ends the first string, both "
create a double-quoted string with '
(escaped) in it, then the last '
starts the second string.
Escaping double quotes is a lot easier and simply requires \"
.
To expand a variable (to access its value), you need to prepend its name with $
:
Mmmm… not really want we want!
!! Single quotes don’t expand variables.
Create a script called name.sh
with the following content:
You can now pass a variable to this script with:
My name is Marie.
You can pass several variables to a script. Copy name.sh
to name2.sh
and edit name2.sh
to look like the following:
My name is Marie and I am 43 years old.
You can also pass any number of variables to a script:
argument1 argument2 argument3 argument4
!! Make sure not to add a space after the comma.
Wildcards are really powerful to apply a command to all the elements having a common pattern.
For instance, we can delete all the files we created earlier (file1.sh
, file2.sh
, etc.) with a single command:
!! Be very careful that rm
is irreversible. Deleted files do not go to the trash: they are gone.
To apply a set of commands to all the elements of a list, you can use for loops. The general structure is as follows:
Let’s create the script names.sh
:
Now let’s run it with a list of arguments:
Patrick
Paul
Marie
Alex
This is a rather silly example, but bear with me and let’s imagine that it actually makes sense (of course, you don’t write that many thesis chapters so you would probably never automate these tasks…)
So… let’s imagine that each time you write a thesis chapter, you do the same things:
.gitignore
file in which you put the data subdirectory.Your turn:
Write a script that would do all this, then test the script.
Give it a try on your own before looking at the solution below…
Here is what the script looks like (let’s call it chapter.sh
):
#!/bin/bash
mkdir $1
cd $1
mkdir src data results ms
touch src/$1.py ms/$1.md
git init
echo data/ > .gitignore
You then run the script:
You can verify that all the files and directories got created with:
chapter1/
├── data
├── ms
│ └── chapter1.md
├── results
└── src
└── chapter1.py
and:
./ ../ data/ .git/ .gitignore ms/ results/ src/
You can also verify the content of your .gitignore
file with:
data/
One very useful (although very dense) resource is the Bash manual.
You can also get information on Bash from within Bash with:
and:
There are also countless resources online and don’t forget to Google anything you don’t know how to do: you will almost certainly find the answer on StackOverflow or some Stack Exchange site.
Comments
Anything to the left of
#
is ignored by the interpreter and is for human consumption only.