Features
Bash is a Turing-complete language and provides a large variety of features.
Some of them are common to most popular programming languages:
- variables
- conditional statements
- loops
- functions
- IO & file operations
- etc
Others are specific to bash and the terminal environment:
- pipes
- job controls
- shell expansions
- special variables
- command history
- etc
This course aims to provide you with working knowledge of bash and the Unix ecosystem, but CANNOT cover all the topics in detail
Operational modes
Bash can be used either:
-
in interactive mode: commands are executed as soon as the user hits enter.
-
for scripts: they are executed to completion and can accept variable arguments
Interactive mode
This is an example of a minimal prompt.
$
It signifies that the shell is ready to accept commands.
The prompt can be customized to include any desirable information such as:
- the current directory
- the machine name
- the current user
- the git branch
- the exit code of the last command
- and more
in the examples we will exclude the prompt in order to simplify the copy/pasting of the sample commands
Hello world
# a hash indicates a comment, anything after it is ignored
echo 'Hello World!'
Once the user submits the command, it executes, and prints the output to the screen.
The echo
command prints the provided argument to standard out
Beware: Bash is case-sensitive, so trying
EcHo 'hello world'
might NOT produce the expected result
Anatomy of a command
All commands in bash follow the following general structure:
[variables] [command] [options] [arguments] [redirects] [operators]
The command is the only mandatory element, everything else is optional
Command parsing order
Bash processes commands in this order:
- History expansion (if enabled)
- Quote removal and word splitting
- Expansions (brace, tilde, parameter, arithmetic, command substitution, pathname)
- Redirection setup
- Command execution
Output
There are 2 main output streams:
-
standard output (stdout) for regular program output
-
standard error (stderr) for error messages and diagnostics.
By default, both streams are displayed on the terminal.
Command types
There are several types of commands in bash.
When trying to execute a command bash will search for it in this order:
- aliases
- keywords
- functions
- built-ins
- external programs (resolved through
$PATH
)
Use the type
built-in command to check the type of another command.
type grep
# prints: grep is /usr/bin/grep
type if
# prints: if is a reserved word
type cd
# prints: cd is a shell builtin
type ll
# prints: ll is an alias for ls -alh
Built-ins and keywords
Use the help
command to get basic information about built-ins and keywords.
help # prints all built-ins and keywords
help if # prints information about the if keyword
Aliases
Use the alias
command to view or define aliases.
alias # prints all aliases
alias ll='ls -alh' # define a new alias
NOTE: there must be NO spaces around the
=
sign. Also, unlike other languages, bash handles single and double quotes differently.
Executing specific command variant
# a bit of setup
alias echo='echo "ALIASED:"'
echo "test"
# uses alias, prints: ALIASED: test
builtin echo "test"
# uses built-in, prints: test
command echo "test"
# uses external, prints: test
Options and arguments
Each command may accept any number of options and/or arguments.
-
Options usually start with a
-
and modify the behaviour of the command. -
Arguments represent data to be used be the command
For example, the -t
option makes the type
command return a single word output
type grep
# prints: grep is /usr/bin/grep
type -t grep
# prints: file
Usually options precede arguments
Exit status
Because bash prints both standard output and errors to the terminal, it might be hard to determine whether a command succeeded.
Fortunately, bash provides a special variable $?
to indicate the exit status of the last command.
A value of 0
means success. Any other (positive number) indicates an error.
type ls
echo $?
# prints 0
type xxx-no-such-command
echo $?
# prints 1
Which is NOT a valid command type?
- built-in
- file (external)
- interactive
- alias
- function
Variables
-
Bash provides a large number of built-in variables.
-
External programs and the operating system also expose a lot of variables.
-
You can define your own variables and expose them to the system.
Use the env
command to see all variables defined on the system.
Or echo
to print the value of a specific variable:
echo $BASH_VERSION
# prints: bash-5.3
NOTICE the
$
character used to reference the variables
Special variables
There are many pre-defined and built-in variables depending on the specific environment. Some useful ones are:
$TERM # the name / type of the terminal
$SHELL # the name of the shell (e.g bash)
$PATH # : separated list of directory
$EDITOR # default text editor
$USERNAME # the login name of the current user
Defining variables
To define your own variables use the NAME=value
syntax.
You can define multiple variables on the same line.
MY_VAR='hello' fruit='banana'
echo $fruit $MY_VAR
# prints: banana hello
NOTICE there is NO
$
character when defining variables.
While it is NOT required for variables to be in ALL CAPS, it is a common convention, especially for global variables.
Variable scope
By default variables are scoped to the current shell.
Use the export
keyword to make a variable global:
export MY_COLOR='green'
export MY_THEME='dark'
export MY_FONT='Plex Mono'
One variable, multiple terminals
Define a normal variable in one terminal window and try printing it in another. Export a variable and trying printing it in another window as well.
Variables can also be scoped to a specific command:
date
# prints: current date in local time zone
TZ=UTC date
# prints: current date in UTC
echo $TZ
# prints nothing, TZ was only defined for that command
The $
character is used for variable expansion.
It allows multiple advanced features:
my_var='abcdef'
echo ${my_var}
# same as echo $my_var
echo ${#my_var}
# prints: 6 - the length of the value
echo ${my_var^^}
# prints: ABCDEF - all uppercase
echo ${my_var:1:3}
# prints: bcd - subset of characters
Single vs double quotes
Single quotes denote a literal string, while double quotes allow for variable expansion.
echo '$MY_VAR test'
# prints: $MY_VAR test
echo "$MY_VAR test"
# prints: hello test
It is recommended to always use quotes.
While bash allows unquoted values, this may lead to hard-to-debug problems.
Subshells
By default, the output of a command goes to stdout. But there are ways to redirect or capture the result of a command:
today=date
echo $today
# doesn't work.. prints the literal 'date'
today=$(date)
echo $today
# works! prints today's date
Subshells can also be used to pass the output of one command as an argument to another:
du -h $(which ls)
# print: 40K /bin/ls
du
returns the size of a filewhich
is similar to type, but resolves$PATH
first
Pipes
Another way of redirecting the output of a command is by using a pipe |
:
env | grep MY_
# prints all global variables that contain the string MY_
Using a pipe we are redirecting the output of the first command to the stdin of the second.
Customize your prompt
Use bash to customize your prompt. Explore options for what information would be most useful to you. Play around with fun colors and special symbols.
Hint: to modify your prompt set a value to the PS1
special variable.