User's introduction to the Bash shell
Bash is (as of today)This de facto shell on most systems you’ll get in touch with: Linux, macOS, and the WSL on Windows 10.
Update: Since Catalina (Autumn 2019) start using zsh macOS
There are some historical reasons that make Bash the most popular shell in the world. Back in 1989, when it was first released, the technological world was very different. At the time, most software in the UNIX world was closed source. Unix itself is proprietary and closed source.
To use a UNIX system, you must use a shell program.
The most popular shell at the time was closed source and proprietary, and you had to pay to use it. It is a Bourne shell and can be used in
/bin/shcommand. It is called "Bourne" because its creator is Steve Bourne.
Richard Stallman (Richard Stallman) in those years with the GNU project (later used on Linux) was about to completely change everything and started the open source revolution. The GNU project needed a shell, and with the help of the Free Software Foundation, Bash was born. Inspired by Bourne Shell, Bash meansByrne shells againIt is an important part of the GNU Project and is probably one of the most successful software we still use today.
Bash can run all scripts written for the script
sh, This is a mandatory feature it adopts, and since the beginning, more features have been introduced to provide users with a better experience. Since its early days, Bash has made many improvements. This tutorial describes the most popular and useful features you can use.
Bash's first step
Since Bash is the default shell in many systems, all you need to do to start a bash shell is
- Log in to the system (if it is a server)
- Open your terminal (if it is your computer)
Look at memacOS terminal guideMore information about using Terminal on Mac.
After startup, you should see a prompt (usually with
How do you know that the shell is running bash? Try to enter
helpThen press Enter.
Look? We just tell Bash to execute
helpcommand. This command shows you the version of Bash you are running and a list of commands that can be used in turn.
Warning: Did you see my version? It is 3.2.57. This is the default version of Bash that comes with macOS, which does not include later versions for licensing issues. The Bash version started in 2014. Use Homebrew to install the latest Bash 5.x by typing
brew install bash.
Unless you are creating, you will never use any of the commands listed in the bash help.Shell scriptOr advanced stuff.
99% of the shell usage every day is to navigate in folders and perform things such as
cdAnd other public UNIX utilities.
Browse file system
To browse the file system, you will use
lscommand. It can be in
/bin/lsAnd because Bash has
/binThe folder is in its path list, you only need to enter
lsList the files in the current folder. You usually start with the home folder, which depends on the system, but under macOS
/Users. My home folder is in
/Users/flavio. This has nothing to do with Bash, it is more of a UNIX file system, but the parameters overlap, and if you have never used Shell, it is good to know this.
To navigate to other folders, use
cdCommand, followed by the name of the folder you want to move to:
cd ..Return to the parent folder.
According to your Bash configuration, you will see the current folder displayed before the prompt (
$Symbol). Or you may not know, but you can always know where you are by typing
pwdThen press Enter.
Command line editing
When writing commands in the shell, please note that you can use the arrow keys to move left and right. This is a shell function. You can move the command around, press the backspace button and correct the command. Press down
enterThe key tells the shell program to let the system execute the command.
This is normal and acceptable behavior, but it may make early UNIX users "wow".
Keyboard combinations allow you to edit quickly without having to touch the arrow keys:
ctrl+dDelete the currently selected character
ctrl+fGo to the character on the right
ctrl+bGo to the character on the left
When moving around in the file system, a nice feature of Bash is auto-completion. Try to enter
cd Docthen press
tabThe key to making Bash autocomplete
cd Documents. If there are multiple choices for the first character, Bash will return to your list, so you can enter a few more characters to help disambiguate, then press
Shell can automatically complete the file name or the command name.
Using the shell, we can run commands available on the system. We can add the full path in front of the command (e.g.
/bin/lsList the files in the folder), but the shell has the following concepts:PathSo we can enter
lsAnd it knows where to find most commands (and we can add folders to this path through configuration).
The command accepts parameters. E.g
ls /binWill list all files in that file
The parameter starts with a dash
lsHidden files are also displayed. By convention, hidden files refer to dots (
Common Shell commands
There are many commands pre-installed on any system, and they vary greatly, depending on whether you are running Linux/macOS or a Linux distribution.
However, let us briefly summarize the most common shell commands you can run. Shell itself does not provide these commands, but command line commands that can be invoked through Shell.
Whenever you encounter a problem, for example, you don’t know the function of the command or how to use it, please use
man. It allows you to get help with all the commands I will list, and more. run
These are the file system commands:
rmDelete files or folders
mvMove the file to another folder, or change the file name
pwdShow current working directory
mkdirCreate a folder
Every file on the Unix file system has permissions.
chmodAllow you to change those (no discussion right now), and
chownAllows you to change filesowner.
grepThere are two super useful commands for working with files.
emacsIt is an editor that is usually installed.
whereisOn macOS, displays the location of the command on the system.
Of course, there are more commands, but you may encounter these commands frequently.
Excuting an order
cdAs I mentioned, these commands are located in
/binfolder. As long as it is an executable file, you can execute any file by typing its full path, for example
/bin/pwd. The command does not need to be in
/binFolder, then you can use
For example, if you have a
/Users/flavio/scriptsFolder, you can run
Or you can run
/Users/flavio/scripts/runmeFrom Bash, no matter where your current folder is.
Whenever you run a command (if it is a long-running program), your shell will be completely owned by the command. You can terminate the command with
You can run at any time
jobsView the job you are running and its status.
$ jobs Job Group State Command 1 72292 stopped ftp
Another useful command is
pswhich lists the processes running.
$ ps PID TTY TIME CMD 19808 ttys000 0:00.56 /usr/local/bin/fish -l 65183 ttys001 0:04.34 -fish 72292 ttys001 0:00.01 ftp
topshows the processes and the resources they are consuming on your system.
A job or process can be killed using
uparrow key will show you the history of the commands you entered. Again, this is a shell feature. Pressing the
downarrow key will let you navigate back and forth in time to see what commands you entered previously, and pressing
enterwill let you run that command again.
This is a quick access to the command history. Running the
historycommand will show you all the commands entered in the shell:
When you start typing a command, Bash can autocomplete it by referencing a previously entered command in the history. Try it by pressing
To be honest I find the Fish shell implementation of this to be much better and easier
Setting your default shell
There are many more shells other than Bash. You have Fish, ZSH, TCSH, and others. Any user on the system can choose its own shell.
You set your default login shell by running the
chsh -s chsh -s /bin/bashcommand. You’ll almost never need to do that, unless it was previously changed, for example with Fish:
chsh -s /usr/local/bin/fish
I noted before that you might (or might not) see your current working directory in the Bash prompt. Where is this determined? In the Bash configuration!
There’s a bit of confusion here because Bash uses a different configuration file for different scenarios, and it also reads multiple configuration files.
Let’s give some order to this confusion. First, there’s a big distinction whether Bash is initialized as a login shell or not. By login shell we mean that the system is not running a GUI (Graphical User Interface) and you log in to the system through the shell. That’s the case of servers, for example.
In this case, Bash loads this configuration file:
and then looks in the user home folder and looks for one of these files, in order, executing the first one it finds:
~/.bash_profile ~/.bash_login ~/.profile
~means your home folder (it’s automatically translated by Bash)
This means that if there’s a
~/.profileare never run, unless explicitly executed in
If instead of being a login shell Bash is run like I do with macOS, for example, as a normal application, the configuration files change. Bash loads first
Sometimes you have programs that use environment variables. Those are values that you can set outside of the program, and alter the execution of the program itself. An API key, for example. Or the name of a file.
You can set an environment variable using the syntax
The value can contain white spaces, by using quotes
A bash script can use this value by prepending a dollar sign:
Also other programming languages commands can use environment variables, for example here’s how to read environment variables with Node.js.
The system sets up some environment variables for you, like
$HOMEyour home folder
$LOGNAMEyour user name
$SHELLthe path to your default shell
$PATHthe path where the shell looks for commands
You can inspect their value by prepending
echo $LOGNAME # flavio echo $HOME # /Users/flavio
A special environment variable: $PATH
I mentioned the $PATH variable. This is a list of folders where the shell will look into when you type a command. Folders are separated by a colon
:and they are written in order - Bash will look into the first, search for the command you asked for, and run it if it finds it. Otherwise if goes to the next folder and so on.
My path is currently:
bash-5.0$ echo $PATH /usr/local/bin:/usr/bin: /bin:/usr/sbin: /sbin:/usr/local/go/bin
You typically edit this in the
~/.bashrcfile by prepending or appending items:
PATH = "$PATH:/Users/flavio/bin"
Using aliases we can set up shortcuts for common commands. You can give a quick name to a complex combination of parameters, for example.
You define an alias using the syntax
if there’s a space in the command you use quotes:
One alias I commonly add to my system is
alias ll="ls --al"
You normally define aliases in your
Just be careful with quotes if you have variables in the command: using double quotes the variable is resolved at definition time, using single quotes it’s resolved at invokation time. Those 2 are different:
alias lsthis="ls $PWD" alias lscurrent='ls $PWD'
$PWD refers to the current folder the shell is into. If you now navigate away to a new folder,
lscurrentlists the files in the new folder,
lsthisstill lists the files in the folder you were when you defined the alias.
Advanced command line features
lsand many other commands can make great use of wildcards. You can list all files starting with image:
Or all files ending with image:
or all files that contain image inside the name:
Redirecting output and standard error error
By default, commands started in the shell print out both the output and errors back to the shell. This might not be what you want. You can decide to write the output to a file instead.
Actually, to a /different file/, because in Unix even the screen is considered to be a file. In particular,
0identifies the standard input
1identifies the standard output
2identifies the standard error
You can redirect the standard output to a file by appending
1>after a command, followed by a file name.
Using the same technique you can use
2>to redirect the standard error.
There is a shortcut
1>, since that is used quite a lot.
ls 1> list.txt 2> error.txt ls > list.txt 2> error.txt
&>, redirects /both/ standard output and standard error to a file.
ls &> output.txt
Another frequent thing is to redirect standard error to standard output using
Running a command in the background
You can tell Bash to run a program in the background without it taking control of the shell, by appending
topis a command that lists the processes running, ordered by most resource consuming.
The application that would normally get control of the shell, is now started but nothing seems to happen. You can bring it back into focus by typing
fg(aka *f*ore*g*round), but now we’re entering in the realm of processes and jobs which is a big topic on its own, but a quick overview:
When a command is running you can use
ctrl-Zto pause it and bring it to the background. The shell comes back again in the foreground, and you can now run
bgto move resume execution of that previously paused job.
When you are ready to go back to it, run
fgto bring back that program in the foreground.
You can see all processes running using
ps, and the list shows all the processes
pidnumbers. Using the paused process
pid, you can bring to foreground a specific command, for example
fg 72292. Same works for
You can instruct Bash to run a command right after another ends by separating them with a semicolon:
cd /bin; ls
You can repeat this to queue multiple commands in the same line.
A program can receive input from any file using the
<operator, and save to a file the output using the
echo hello > result.txt wc < result.txt
wcis a command that counts the words it receives as input.
Using pipes, any command output can be used as input for a second command. Use the
|operator to combine the two. In this example,
wcgets its input from the output of
echo hello | wc
&&to combine two commands using “and”. If the first command executes without problems, run the second, and so on.
||to combine two commands using “or”. If the first command executes without problems the second does not run.
!negates the next logical operation:
$ echo hello && echo test hello test $ echo hello || echo test hello $ ! echo hello || echo test hello test
You can use parentheses to combine expressions to avoid confusion, and also to change the precedence:
$ ! (echo hello) || (echo test) hello test $ ! (echo hello || echo test) hello
One of the best features of a shell like Bash is its ability to create programs with it, by basically automating commands execution.
I’m going to write a separate guide on Bash scripting soon, which will be separate from this tutorial because the topic is really more in-depth than what I want to add in this introductory Bash guide.
A quick intro though: a script is a text file that starts with a line that indicates that it’s a shell script (and what shell it requires), followed by a list of commands, one per line. Example:
You can save this as a file
myscriptand make it executable using
chmod +x myscript, and run it using
./means “current folder”).
Shell scripting is outside of the scope of this post, but I want you to know about this. Scripts can have control structures and many other cool things.
This same scripting strategy works for other shells, like Zsh:
Download my free Linux Commands Handbook
More cli tutorials:
- The Bash shell
- Introduction to Bash Shell Scripting
- The Fish Shell
- Shell, watch file content as it populates
- How to exit Vim
- UNIX Editors
- The UNIX Filesystem Commands
- Unix Shells Tutorial
- How to set an alias in a macOS or Linux shell
- A practical guide to Homebrew
- How to fix the xcrun invalid active developer path error in macOS
- The Command Line for Complete Beginners
- Introduction to Linux
- How to find the process that is using a port
- Linux commands: mkdir
- Linux commands: cd
- Linux commands: pwd
- Linux commands: rmdir
- Linux commands: ls
- Linux commands: mv
- Linux commands: cp
- Linux commands: less
- Linux commands: tail
- Linux commands: touch
- Linux commands: cat
- Linux commands: find
- Linux commands: ln
- Linux commands: ps
- Linux commands: echo
- Linux commands: top
- Linux commands: kill
- Linux commands: killall
- Linux commands: alias
- Linux commands: jobs
- Linux commands: bg
- Linux commands: fg
- Linux commands: type
- Linux commands: which
- Linux commands: whoami
- Linux commands: who
- Linux commands: clear
- Linux commands: su
- Linux commands: sudo
- Linux commands: chown
- Linux commands: chmod
- Linux commands: passwd
- Linux commands: open
- Linux commands: wc
- Linux commands: history
- Linux commands: du
- Linux commands: umask
- Linux commands: grep
- Linux commands: man
- Linux commands: uname
- Linux commands: sort
- Linux commands: uniq
- Linux commands: diff
- Linux commands: nohup
- Linux commands: df
- Linux commands: xargs
- Linux commands: gzip
- Linux commands: gunzip
- Linux commands: ping
- Linux commands: traceroute
- Linux commands: tar
- Linux commands: export
- Linux commands: crontab
- Linux commands: dirname
- Linux commands: basename
- Linux commands: printenv
- Linux commands: env
- A short guide to the ed editor
- A short guide to vim
- A short guide to emacs
- A short guide to nano
- Linux, no space left on device
- How to use Netcat