Bash
Bash, apart from being a UNIX shell, is also a programming language in it’s own right. It is commonly referred to as a scripting language because the script is not compiled, but rather interpreted at runtime.
Shebang
A shebang at the top of a Bash script allows you to run the script directly from the command-line as if it was an executable, e.g. by calling ./my_script.sh
. This is because the shebang tells your shell (which may or may not be Bash) to call the mentioned program, and pass in the script as the first parameter.
The recommended shebang to use at the top of a bash script is:
The above variant gives the greatest portability, as different UNIX systems put the bash program at different locations on the system (e.g. OpenBSD and FreeBSD both do not have bash at /bin/bash
). The above shebang is an instruction to run the first bash that is found on the PATH.
A less optimal bash shebang is:
This is not as portable as the bash location is hard-coded into the shebang.
Finally, it is not recommended to use the shebang:
if you want to run bash, as /bin/sh
is usually a symlink to the operating systems default shell, which may or may not be bash (it could also be dash).
Returning From Scripts
The return statement can be used to return from a function within a script. return has nothing to do with the exit code.
The exit code of the last command run in a script is used as the exit code that is returned to the parent program.
You can also use the command exit <number>
at any time to return from the script.
ANSI Escape Codes
Bash supports various ANSI escape codes. This includes the commonly used codes to colour text printed to the terminal.
Getting The Current Script Directory
You can read the current script directory as a string into a variable using the following code:
Command-line Argument Parsing
Command-line argument parsing in bash is notoriously tricky.
Thankfully, some open-source third party libraries come to the rescue. One of the most powerful command-line argument parsing libraries for shell scripts is shflags, a port of the Google gflags library for the UNIX shell.
The simple Hello, World example (taken from their website) is shown below. If you create a file called hello_world.sh
with the following contents:
You could then call this as so:
As shown above, it also supports automatic help! Although the shebang in the above example is #!/bin/sh
, this can be changed to #!/usr/bin/env bash
without any issues.
Refreshing The Current Working Directory After It Was Deleted And Recreated
If the directory you are currently in during a bash session gets deleted and recreated, you may notice that commands like ls don’t work. That is because the directory you were in no longer exists, the new directory is a different directory (different inode) but shares the same name.
To quickly get back to a valid state of the working directory, type:
The works by re-entering a directory with the same path as the old one you are currently in.
Command Substitution
You can use `
(backticks) or $()
for command substitution. For example:
The above command will store the output of the command ls .
(which will be a list of the contents of the current directory) into the variable A
. It will not print the output of ls
to the console (as it usually would). Now if we went:
It is recommended that you use the $()
syntax rather than `
, as $()
is standardized by POSIX and should work for most shells.
Dealing With Special Characters In Filenames And Directories
You can run into issues when trying to create, copy, move, delete or otherwise manipulate files and directories in bash when the names contain special characters such as -
, $
, #
and ;
(which are all allowed to be included in file names and directory names as per the UNIX specification).
The following sections show you how to deal with these special characters.
Hyphens
File names which start with hyphens can be troublesome to manage. Most programs (note: not the shell, but the program) will interpret the hyphen as a option specifier and try and parse the start of the filename as an option.
There are two common ways to deal with this problem. The first is to use the --
specifier. For most common utility programs (e.g. touch
, mv
, cp
, rm
) everything after a --
is not parsed for options:
or you explicitly include the current directory in the path:
Hashes
Hashes cannot be dealt with in the same way as hyphens, because they are interpreted differently by the shell (e.g. bash), not the program. The --
method will not work. However, you can prefix the file with the current directory:
You can enclose the filename in '
quotes, which tell bash not to interpret the #
:
Semicolons
Bash uses semicolons to delimit separate commands, and so you have to enclose filenames and directories in single quotes ('
), which will tell Bash not to interpret the ;
as a command separator: