Bash is the de facto shell on most widely used systems: Linux, macOS, and WSL on Windows 10/11.
Note: Starting from macOS version 10.15 Catalina, the default shell is zsh, not bash.
There are historical reasons why bash became the most popular shell in the world. Back in 1989 when it was first released, the technology world was very different. At that time, much of the software in the UNIX world had closed source code. Unix itself had patents and closed source code.
To use a UNIX system, you had to use a shell.
The most popular shell at that time was the Bourne Shell (sh), available under the command /bin/sh
. It was called “Bourne Shell” because its creator was Steve Bourne.
Richard Stallman, with the GNU Project (and later Linux), almost revolutionized everything, starting with the Open Source revolution. The GNU Project needed a shell, and with the help of the Free Software Foundation, Bash was born. Inspired by the Bourne Shell, Bash stands for Bourne Again Shell, and it became a key component of the GNU Project, and one of the most popular software still in use today.
Bash can run scripts written for sh
, which was a must-have feature for adoption, and it also introduced many new features not found in the Bourne Shell. From day one, it offered a great user experience and has seen many improvements since then. In this blog, we will discuss the most popular and useful features of Bash that you can try.
Getting Started with Bash
Since Bash is the default shell on every system, the first thing you need to do to start using the bash shell is:
- Log into the system if it’s a server
- Open a terminal if it’s a laptop/computer
When you first open the terminal, you will see a prompt (usually $
or #
).
How do you know if your shell is bash? Try typing the command echo $SHELL
in your terminal. If you get /bin/bash
, then you are using bash, or try typing help
and press enter.
See? We just asked bash to execute the help
command. This command will display the version of bash you are using, as well as a list of available commands in bash.
More often than not, you will never use the list of available commands in bash help
, unless you are writing bash scripts. But, it will be useful if you want to know what you can do in bash.
99% of the time, you will use bash to navigate files and directories and run commands like ls
, cd
, and other common utility commands.
Navigating the File System
To navigate the file system, you will use the ls
command, which is available under /bin/ls
. Since bash has the /bin
folder in $PATH, you can run the ls
command without typing /bin/ls
.
ls
is the command to list the contents of a directory. If you do not specify a directory, it will list the contents of the current directory.
You usually start in the /home
or /Users
folder on macOS. My home folder is currently /home/memet
.
memet@zxce3 ~ $ ls
Desktop Documents Downloads Music Pictures Public Templates Videos
To navigate to another directory, you can use the cd
(change directory) command. If you want to go back to the previous directory, you can use the cd -
command.
memet@zxce3 ~ $ cd Desktop
memet@zxce3 ~/Desktop $ cd -
memet@zxce3 ~ $
cd ..
will take you to the parent directory, and cd ../..
will take you two levels up.
memet@zxce3 ~ $ cd ..
memet@zxce3 /home $ cd ../..
memet@zxce3 / $
Depending on your Bash configuration, you will see the current folder in the prompt (symbol $
). If you are using a simpler prompt, you can use the pwd
command to see the current directory.
memet@zxce3 ~ $ pwd
/home/memet
pwd
stands for print working directory
Command Editing
When you type a command in the terminal, you can use several keyboard shortcuts to edit the command you typed. You can use the arrow keys to move the cursor, and the backspace key to delete characters before the cursor. If you want to delete the entire command, you can use the Ctrl + u
command. Pressing enter
will execute the command you typed.
This is normal and acceptable, but something that wowed early UNIX/Linux users.
Keyboard shortcuts help you edit the command you typed, and this is very useful when you want to edit a long command without using the arrow keys.
Ctrl + a
will move the cursor to the beginning of the commandCtrl + e
will move the cursor to the end of the commandCtrl + f
will move the cursor one character to the rightCtrl + b
will move the cursor one character to the leftCtrl + k
will delete all characters after the cursorCtrl + u
will delete all characters before the cursorCtrl + d
will delete the character in front of the cursor
There are many more keyboard shortcuts you can use to edit the command you typed.
Autocomplete
One of the most useful features in bash is autocompletion. It helps you type commands quickly and avoid typos. Try typing cd Doc
and pressing tab
. Bash will complete the command for you. If there are multiple options for the characters you typed, you can type more characters and press tab
again.
memet@zxce3 ~ $ cd Do
Documents/ Downloads/
memet@zxce3 ~ $ cd Doc
memet@zxce3 ~ $ cd Documents/
memet@zxce3 ~/Documents $
Autocompletion also works for file and directory names. Try typing ls Doc
and pressing tab
. Bash will complete the directory name for you.
memet@zxce3 ~ $ ls Doc
Documents/ Downloads/
memet@zxce3 ~ $ ls Documents/
image.png image2.png image3.png
Autocompletion also works for commands
Shell Commands
Using the shell, we can run commands available on our system. We can prefix commands with the full path (e.g., /bin/ls
or /usr/bin/ls
to list files and directories), but the shell has the concept of path
, so we just need to type ls
, and it will look for the command in the specified paths.
Commands accept arguments. For example, ls /bin
will list all files in the /bin
folder.
Parameters start with a dash (-
) and can be combined. For example, ls -a
will list all files, including hidden files (those starting with a dot .
). ls -l
will list files in a detailed format.
Commonly Used Commands
There are many built-in commands on all systems, and they vary depending on whether it’s Linux/Unix or macOS or even the Linux distribution you are using.
However, let’s cover the most common and widely used ones.
When you encounter problems, such as not knowing a command or how to use it, you can use the man
command to view the documentation for that command.
Here is a list of commonly used system commands:
Command | Description |
---|---|
ls | List files and directories |
cd | Change the current directory |
pwd | Print the current directory |
mkdir | Create a new directory |
mv | Move or rename files or directories |
cp | Copy files or directories |
rm | Remove files or directories |
Every file in Unix has permissions, and you can use the chmod
command to change them (not covered here). The chown
command changes the file owner.
cat
, tail
, and grep
are very useful commands for files. cat
displays the contents of a file, tail
shows the end of a file, and grep
searches for a string in a file.
find
and locate
are commands to search for files. find
searches for files in the current directory, and locate
searches for files across the entire system.
tar
and gzip
are commands to compress files. tar
compresses files, and gzip
compresses already compressed files.
pico
, nano
, vim
, and emacs
are commonly installed and used editors.
whereis
and which
are commands to find the location of commands. whereis
finds the location of commands, and which
finds the location of commands that will be executed.
There are many more commands you can use on your system, and these are some of the commands you will likely use frequently.
Running Commands
The cd
and ls
commands, as explained above, are found in the /bin
folder. You can execute any file as long as it is an executable file by typing the full path, for example, /bin/pwd
. Commands do not require the /bin
folder, and you can execute files in the current folder with the ./
path indicator.
For example, if you have a file yamete
in the /home/memet/scripts
folder, you can run:
cd /home/memet/scripts
Then run ./yamete
to execute the file.
Or you can run /home/memet/scripts/yamete
from Bash, regardless of the current folder.
Jobs
When you run any command, if it is a long-running program, your shell is taken over by that program. You can stop the command by pressing ctrl + c
.
You can run commands in the background by adding &
at the end of the command. For example, sleep 1000 &
will run the sleep
command for 1000 seconds in the background.
You can see a list of running commands with the jobs
command. You can stop commands with the kill
and killall
commands.
memet@zxce3:~$ sleep 1000 &
[1] 1234
memet@zxce3:~$ jobs
[1]+ Running sleep 1000 &
memet@zxce3:~$ kill 1234
memet@zxce3:~$ jobs
[1]+ Terminated sleep 1000 &
Background commands will stop if you close your shell.
Another useful command is ps
to see a list of running processes.
memet@zxce3:~$ ps
PID TTY TIME CMD
123 pts/0 00:00:00 bash
456 pts/0 00:00:00 ps
And top
to see a real-time list of running processes.
A job process can be stopped using kill <PID>
.
Command History
Pressing the up
arrow key will show the commands you previously ran. This is a shell feature. Pressing the down
arrow key will help you navigate back to the most recently run commands. Pressing enter
will run the command again.
This is quick access to the commands you previously ran. Running the history
command will display a list of all the commands you previously ran.
memet@zxce3:~$ history
1 ls
2 cd /home/memet
3 ls
4 cd /home/memet/scripts
5 ls
6 history
When you start typing a command, Bash can autocomplete the command you previously ran by referencing the commands you previously ran. Try pressing esc
and then tab
.
Honestly, I found the implementation of the fish shell to be better and easier. Maybe I’ll discuss it later.
Setting the Default Shell
There are many shells besides Bash, such as Fish, Zsh, TCSH, and others. Each user on the system can choose the shell they want. You can change the default shell with the chsh
command.
memet@zxce3:~$ chsh
Changing shell for memet.
Password:
New shell [/bin/bash]: /bin/zsh
memet@zxce3:~$ echo $SHELL
/bin/zsh
Customizing Bash
As mentioned earlier, you may (or may not) see the current directory in the bash prompt. Where is this determined? In the Bash configuration file!
There is some confusion here because Bash uses different configuration files for different scenarios, and it also reads multiple configuration files.
Let’s discuss this confusion one by one. First, there is a big difference between whether Bash is initialized as a login shell or a non-login shell. A login shell means that the system is not running in a GUI (Graphical User Interface) and you log into the system through the shell. This is in the context of a server, for example.
In this case, Bash reads the /etc/profile
configuration file.
And look in the user’s home folder, there are configuration files.
~/.bash_profile
~/.bash_login
~/.profile
Where ~
is the user’s home folder (this is automatically translated by Bash).
This means that if there are .bash_profile
, ~/.bash_login
, and ~/.profile
files in the user’s home folder, Bash will read these files. If there are .bash_profile
and ~/.bash_login
files in the user’s home folder, Bash will read the .bash_profile
file first.
If Bash is run as a non-login shell, Bash will read the ~/.bashrc
configuration file.
Environment Variables
Sometimes you have programs that use environment variables. These are values that can be set outside the program, and the program can access them. An API key, for example. Or a path you need to run the program.
You can set an environment variable with syntax like this.
VARIABLE_NAME=VALUE
The value can contain spaces and special characters by using quotes.
VARIABLE_NAME="THIS IS THE VALUE"
Bash scripts can use variables with the syntax $VARIABLE_NAME
.
memet@zxce3:~$ VARIABLE_NAME="THIS IS THE VALUE"
memet@zxce3:~$ echo $VARIABLE_NAME
THIS IS THE VALUE
Bash also provides some variables you can use, such as:
$HOME
for the user’s home folder$PATH
for the path accessible by programs$SHELL
for the currently running shell$USER
for the username
You can see the contents of these variables using the echo
command.
memet@zxce3:~$ echo $HOME
/home/memet
memet@zxce3:~$ echo $SHELL
/bin/bash
Special Environment Variable: $PATH
$PATH
is a variable that contains a list of paths accessible by programs. The shell will look at this when you type a command. Folders are separated by colons :
and are ordered from left to right - Bash will look at the first one, search for the command there, and if not found, look at the second one, and so on.
My current path is like this.
memet@zxce3:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin/:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/games:
You can edit this in the ~/.bashrc
file by adding the path you want.
PATH=$PATH:/home/memet/scripts
Aliases
Aliases are shortcuts for commands you frequently use. For example, you can create an alias for git status
with gst
.
memet@zxce3:~$ alias gst='git status'
memet@zxce3:~$ gst
On branch master
Your branch is up to date with 'origin/master'.
To define an alias, use the syntax like this.
alias <alias>=<command>
If you want to create an alias for a long command, you can use quotes.
alias <alias>="<command>"
You can also define aliases in the ~/.bashrc
file.
Be careful with quotes if you have variables in the command: using double quotes will resolve the variable at definition time, using single quotes will resolve the variable at call time. These are different.
alias lsnow="ls $PWD"
alias lslater='ls $PWD'
$PWD
refers to the current folder, and if you type lsnow
and lslater
, you will get different results. lsnow
will display the contents of the current folder, while lslater
will display the contents of the folder where you defined the alias.
Advanced Command Line Features
Wildcards
ls
and many other commands can use wildcards, you can list all files starting with a
with the command ls a*
.
memet@zxce3:~$ ls a*
a.txt ab.txt abc.txt
Or you can list all files ending with .txt
with the command ls *.txt
.
memet@zxce3:~$ ls *.txt
a.txt ab.txt abc.txt
Or all files ending with b
or c
with the command ls *b* *c*
.
memet@zxce3:~$ ls *b* *c*
a.txt ab.txt abc.txt
Redirecting Output and Standard Error
By default, commands started in the shell send both output and error to the terminal. This may not be what you want, you can specify where the output should go.
Actually, to /another file/, because in Unix even the screen is considered a file. Specifically:
0
is standard input1
is standard output2
is standard error
You can redirect standard output to a file by adding 1>
at the end of the command, followed by the file name.
Using the same technique, you can redirect standard error to a file by adding 2>
.
There is a shortcut >
for 1>
, as it is used the most.
Example:
ls 1> output.txt 2> error.txt
ls > output.txt 2> error.txt
Another shortcut, &>
, redirects /both/ standard output and standard error to the same file.
ls &> output.txt
Another common thing you might do is redirect both standard output and standard error to /the same/ place. You can use 2>&1
to redirect standard error to the same place as standard output.
ls 1> output.txt 2>&1
Running Commands in the Background
You can tell Bash to run a command in the background without taking control of the shell by adding &
at the end of the command.
memet@zxce3:~$ top &
[1] 1234
top
is a command that displays a list of running processes on the system.
[1] 1234
is a message indicating that the command is running in the background, and the process number is 1234
.
An application that usually takes control of the shell is now running as if nothing happened. You can bring it back to the shell by typing fg
(foreground), but now we are entering the realm of processes and jobs, which is a big topic on its own. Here is a brief overview:
When a command is running, you can use Ctrl + Z
to pause the command and move it to the background. The shell returns to the foreground, and you can now run bg
to resume the paused command in the background.
When you are ready to return to it, you can use fg
to bring the command back to the foreground.
You can also see a list of running background processes with the ps
command, and the list shows all process pid
numbers. Using the pid
of the paused process, you can bring the process back to the foreground with the fg <pid>
command. The same applies to bg
.
memet@zxce3:~$ ps
PID TTY TIME CMD
1234 pts/0 00:00:00 top
1235 pts/0 00:00:00 bash
1236 pts/0 00:00:00 ps
memet@zxce3:~$ fg 1234
top
Command Queue
You can ask Bash to run a command after another command finishes by separating them with a semicolon ;
.
memet@zxce3:~$ sleep 5; echo "done"
done
You can repeat the command queue on the same line.
Redirecting Output
Programs can receive input from any file using the <
operator, and redirect output to another file using the >
operator.
memet@zxce3:~$ echo "hello" > output.txt
memet@zxce3:~$ wc < output.txt
1 1 6 output.txt
wc
is a command that counts the number of words, lines, and characters in a file.
Pipe
A pipe is an operator that directs the output of one command to the input of another command. It is a very effective way to process data. It is similar to the >
operator, but more flexible. Use the |
operator to combine commands. For example, wc
gets input from the output of echo hello
and counts the number of words, lines, and characters in the string.
memet@zxce3:~$ echo "hello" | wc
1 1 6
Command Grouping
Use &&
to combine two commands with the word “and”. If the first command succeeds, the second command will run. If the first command fails, the second command will not run, and so on.
memet@zxce3:~$ false && echo "success"
memet@zxce3:~$ true && echo "success"
success
Use ||
to combine two commands with the word “or”. If the first command fails, the second command will run. If the first command succeeds, the second command will not run, and so on.
memet@zxce3:~$ false || echo "success"
success
memet@zxce3:~$ true || echo "success"
memet@zxce3:~$
The !
operator reverses the value of a command.
memet@zxce3:~$ !true
false
memet@zxce3:~$ !false
true
You can also use parentheses to group expressions to avoid confusion and change the execution priority.
memet@zxce3:~$ (true && false) || true
true
memet@zxce3:~$ ! (true && false) || true
false
Shell Script
One of the best features of shells like Bash is the ability to create programs that can be run in the shell, essentially automating command execution.
I will create several blogs about this later, which will be divided into several tutorials. Why not combine them into one? Because the topic is much deeper and longer.
A brief introduction: a script is a text file that starts with a line indicating that it is a shell script (and what shell it needs), and then contains shell commands to be executed.
#!/bin/bash
echo "hello"
You can save this as a script
file and make it executable with the chmod +x script
command. Then you can run the file with the ./script
command (./
is the current file location).
Shell scripting is actually beyond the scope of this tutorial, but I want you to know about it. So I will create some tutorials on shell scripting later. Scripts can do many things, such as taking input from users, processing data, and much more.
Scripting strategies also work in many other shells, such as zsh
, fish
, and csh
.
Example fish shell script
#!/usr/bin/fish
echo "hello"
Please leave comments and suggestions for this blog. Thank you.