118 views
Posted: 28 Apr 2021 (12:45)
Last Edited: 29 Apr 2021 (09:18)
@r___75
Until about a year ago, I worked almost exclusively within the macOS and Ubuntu operating systems. On both of those OSes, bash
is my default shell. I've acquired a general understanding of how bash
works over the past six or seven years and would like to give an overview of some of the more common / useful commands for those just getting started. If you think you know everything there is to know about bash
, take a look below anyway -- I've included some tips and reminders of flags you may have forgotten about, which could make your work a bit easier.
The commands below are laid out in a more-or-less narrative style, so if you're just getting started with bash
, you can work your way through from the beginning to the end. Things generally get less common and more difficult toward the end.
Modern filesystems have directory (folder) trees, where a directory is either a root directory (with no parent directory) or is a subdirectory (contained within a single other directory, which we call its "parent"). Traversing backwards through the file tree (from child directory to parent directory) will always get you to the root directory. Some filesystems have multiple root directories (like Windows' drives: C:\
, A:\
, etc.), but Unix and Unix-like systems only have a single root directory called \
.
pwd / ls / cd
When working within a filesystem, the user is always working within some directory, which we call the current directory or the working directory. Print the user's working directory with pwd
:
[ andrew@pc01 ~ ]$ pwd /home/andrew
List the contents of this directory (files and/or child directories, etc.) with ls
:
[ andrew@pc01 ~ ]$ ls Git TEST jdoc test test.file
Bonus:
Show hidden ("dot") files with ls -a
Show file details with ls -l
Combine multiple flags like ls -l -a
You can sometimes chain flags likels -la
instead ofls -l -a
Change to a different directory with cd
(change directory):
[ andrew@pc01 ~ ]$ cd TEST/ [ andrew@pc01 TEST ]$ pwd /home/andrew/TEST [ andrew@pc01 TEST ]$ cd A [ andrew@pc01 A ]$ pwd /home/andrew/TEST/A
cd ..
is shorthand for "cd
to the parent directory”:
[ andrew@pc01 A ]$ cd .. [ andrew@pc01 TEST ]$ pwd /home/andrew/TEST
cd ~
or just cd
is shorthand for "cd
to my home directory" (usually /home/username
or something similar):
[ andrew@pc01 TEST ]$ cd [ andrew@pc01 ~ ]$ pwd /home/andrew
Bonus:
cd ~user
means "cd
touser
's home directory
You can jump multiple directory levels with cd ../..
, etc.
Go back to the most recent directory with cd -
.
is shorthand for "this directory", socd .
won't do much of anything
; / && / &
The things we type into the command line are called commands, and they always execute some machine code stored somewhere on your computer. Sometimes this machine code is a built-in Linux command, sometimes it's an app, sometimes it's some code that you wrote yourself. Occasionally, we'll want to run one command right after another. To do that, we can use the ;
(semicolon):
[ andrew@pc01 ~ ]$ ls; pwd Git TEST jdoc test test.file /home/andrew
Above, the semicolon means that I first (ls
) list the contents of the working directory, and then I (pwd
) print its location. Another useful tool for chaining commands is &&
. With &&
, the command to the right will not run if the command to the left fails. ;
and &&
can both be used multiple times on the same line:
# whoops! I made a typo here! [ andrew@pc01 ~ ]$ cd /Giit/Parser && pwd && ls && cd -bash: cd: /Giit/Parser: No such file or directory # the first command passes now, so the following commands are run [ andrew@pc01 ~ ]$ cd Git/Parser/ && pwd && ls && cd /home/andrew/Git/Parser README.md doc.sh pom.xml resource run.sh shell.sh source src target
...but with ;
, the second command will run even if the first one fails:
# pwd and ls still run, even though the cd command failed [ andrew@pc01 ~ ]$ cd /Giit/Parser ; pwd ; ls -bash: cd: /Giit/Parser: No such file or directory /home/andrew Git TEST jdoc test test.file
&
looks similar to &&
but actually fulfils a completely different function. Normally, when you execute a long-running command, the command line will wait for that command to finish before it allows you to enter another one. Putting &
after a command prevents this from happening, and lets you execute a new command while an older one is still going:
[ andrew@pc01 ~ ]$ cd Git/Parser && mvn package & cd [1] 9263
Bonus: When we use&
after a command to "hide" it, we say that the job (or the "process"; these terms are more or less interchangeable) is "backgrounded". To see what background jobs are currently running, use thejobs
command:
[ andrew@pc01 ~ ]$ jobs [1]+ Running cd Git/Parser/ && mvn package &
-h
Type -h
or --help
after almost any command to bring up a help menu for that command:
[ andrew@pc01 ~ ]$ du --help Usage: du [OPTION]... [FILE]... or: du [OPTION]... --files0-from=F Summarize disk usage of the set of FILEs, recursively for directories. Mandatory arguments to long options are mandatory for short options too. -0, --null end each output line with NUL, not newline -a, --all write counts for all files, not just directories --apparent-size print apparent sizes, rather than disk usage; although the apparent size is usually smaller, it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g., '-BM' prints sizes in units of 1,048,576 bytes; see SIZE format below ...
man
Type man
before almost any command to bring up a manual for that command (quit man
with q
):
LS(1) User Commands LS(1) NAME ls - list directory contents SYNOPSIS ls [OPTION]... [FILE]... DESCRIPTION List information about the FILEs (the current directory by default). Sort entries alphabetically if none of -cftuvSUX nor --sort is speci- fied. Mandatory arguments to long options are mandatory for short options too. ...
head / tail / cat / less
head
outputs the first few lines of a file. The -n
flag specifies the number of lines to show (the default is 10):
# prints the first three lines [ andrew@pc01 ~ ]$ head -n 3 c this file has
tail
outputs the last few lines of a file. You can get the last n
lines (like above), or you can get the end of the file beginning from the N
-th line with tail -n +N
:
# prints the end of the file, beginning with the 4th line [ andrew@pc01 ~ ]$ tail -n +4 c exactly six lines
cat
concatenates a list of files and sends them to the standard output stream (usually the terminal). cat
can be used with just a single file, or multiple files, and is often used to quickly view them. (Be warned: if you use cat
in this way, you may be accused of a Useless Use of Cat (UUOC), but it's not that big of a deal, so don't worry too much about it.)
[ andrew@pc01 ~ ]$ cat a file a [ andrew@pc01 ~ ]$ cat a b file a file b
less
is another tool for quickly viewing a file -- it opens up a vim
-like read-only window. (Yes, there is a command called more
, but less
-- unintuitively -- offers a superset of the functionality of more
and is recommended over it.) Learn more (or less?) about less and more at their man
pages.
nano / nedit
nano
is a minimalistic command-line text editor. It's a great editor for beginners or people who don't want to learn a million shortcuts. It was more than sufficient for me for the first few years of my coding career (I'm only now starting to look into more powerful editors, mainly because defining your own syntax highlighting in nano
can be a bit of a pain.)
nedit
is a small graphical editor, it opens up an X Window and allows point-and-click editing, drag-and-drop, syntax highlighting and more. I use nedit
sometimes when I want to make small changes to a script and re-run it over and over.
Other common CLI (command-line interface) / GUI (graphical user interface) editors include emacs
, vi
, vim
, gedit
, Notepad++, Atom, and lots more. Some cool ones that I've played around with (and can endorse) include Micro, Light Table, and VS Code.
All modern editors offer basic conveniences like search and replace, syntax highlighting, and so on. vi(m)
and emacs
have more features than nano
and nedit
, but they have a much steeper learning curve. Try a few different editors out and find one that works for you!
touch
touch
was created to modify file timestamps, but it can also be used to quickly create an empty file. You can create a new file by opening it with a text editor, like nano
:
[ andrew@pc01 ex ]$ ls [ andrew@pc01 ex ]$ nano a
...editing file...
[ andrew@pc01 ex ]$ ls a
...or by simply using touch
:
[ andrew@pc01 ex ]$ touch b && ls a b
Bonus:
Background a process with ^z (Ctrl+z)
[ andrew@pc01 ex ]$ nano a
...editing file, then hit ^z...
Use fg to return to nano [1]+ Stopped nano a [ andrew@pc01 ex ]$ fg
...editing file again...
Double Bonus:
Kill the current (foreground) process by pressing ^c (Ctrl+c) while it’s running
Kill a background process withkill %N
whereN
is the job index shown by thejobs
command
mkdir / rm / rmdir
mkdir
is used to create new, empty directories:
[ andrew@pc01 ex ]$ ls && mkdir c && ls a b a b c
You can remove any file with rm
-- but be careful, this is non-recoverable!
[ andrew@pc01 ex ]$ rm a && ls b c
You can add an "are you sure?" prompt with the -i
flag:
[ andrew@pc01 ex ]$ rm -i b rm: remove regular empty file 'b'? y
Remove an empty directory with rmdir
. If you ls -a
in an empty directory, you should only see a reference to the directory itself (.
) and a reference to its parent directory (..
):
[ andrew@pc01 ex ]$ rmdir c && ls -a . ..
rmdir
removes empty directories only:
[ andrew@pc01 ex ]$ cd .. && ls test/ *.txt 0.txt 1.txt a a.txt b c [ andrew@pc01 ~ ]$ rmdir test/ rmdir: failed to remove 'test/': Directory not empty
...but you can remove a directory -- and all of its contents -- with rm -rf
(-r
= recursive, -f
= force):
[ andrew@pc01 ~ ]$ rm –rf test
mv / cp / ln
mv
moves / renames a file. You can mv
a file to a new directory and keep the same file name or mv
a file to a "new file" (rename it):
[ andrew@pc01 ex ]$ ls && mv a e && ls a b c d b c d e
cp
copies a file:
[ andrew@pc01 ex ]$ cp e e2 && ls b c d e e2
ln
creates a hard link to a file:
# first argument to ln is TARGET, second is NEW LINK [ andrew@pc01 ex ]$ ln b f && ls b c d e e2 f
ln -s
creates a soft link to a file:
[ andrew@pc01 ex ]$ ln -s b g && ls b c d e e2 f g
Hard links reference the same actual bytes in memory which contain a file, while soft links refer to the original file name, which itself points to those bytes. You can read more about soft vs. hard links here.
bash
has two big features to help you complete and re-run commands, the first is tab completion. Simply type the first part of a command, hit the <tab> key, and let the terminal guess what you're trying to do:
[ andrew@pc01 dir ]$ ls <ENTER> anotherlongfilename thisisalongfilename anewfilename [ andrew@pc01 dir ]$ ls t <TAB>
...hit the TAB key after typing ls t
and the command is completed...
[ andrew@pc01 dir ]$ ls thisisalongfilename <ENTER> thisisalongfilename
You may have to hit <TAB> multiple times if there's an ambiguity:
[ andrew@pc01 dir ]$ ls a <TAB> [ andrew@pc01 dir ]$ ls an <TAB> anewfilename anotherlongfilename
bash
keeps a short history of the commands you've typed previously and lets you search through those commands by typing ^r (Ctrl+r):
[ andrew@pc01 dir ]
...hit ^r (Ctrl+r) to search the command history...
(reverse-i-search)`':
...type 'anew' and the last command containing this is found...
(reverse-i-search)`anew': touch anewfilename
mkdir –p / tree
mkdir
, by default, only makes a single directory. This means that if, for instance, directory d/e
doesn't exist, then d/e/f
can't be made with mkdir
by itself:
[ andrew@pc01 ex ]$ ls && mkdir d/e/f a b c mkdir: cannot create directory 'd/e/f': No such file or directory
But if we pass the -p
flag to mkdir
, it will make all directories in the path if they don't already exist:
[ andrew@pc01 ex ]$ mkdir -p d/e/f && ls a b c d
tree
can help you better visualise a directory's structure by printing a nicely-formatted directory tree. By default, it prints the entire tree structure (beginning with the specified directory), but you can restrict it to a certain number of levels with the -L
flag:
[ andrew@pc01 ex ]$ tree -L 2 . |-- a |-- b |-- c `-- d `--e 3 directories, 2 files
You can hide empty directories in tree
's output with --prune
. Note that this also removes "recursively empty" directories, or directories which aren't empty per se, but which contain only other empty directories, or other recursively empty directories:
[ andrew@pc01 ex ]$ tree --prune . |-- a `-- b
df / du / ps
df
is used to show how much space is taken up by files for the disks or your system (hard drives, etc.).
[ andrew@pc01 ex ]$ df -h Filesystem Size Used Avail Use% Mounted on udev 126G 0 126G 0% /dev tmpfs 26G 2.0G 24G 8% /run /dev/mapper/ubuntu--vg-root 1.6T 1.3T 252G 84% / ...
In the above command, -h
doesn't mean "help", but "human-readable". Some commands use this convention to display file / disk sizes with K
for kilobytes, G
for gigabytes, and so on, instead of writing out a gigantic integer number of bytes.
du
shows file space usage for a particular directory and its subdirectories. If you want to know how much space is free on a given hard drive, use df
; if you want to know how much space a directory is taking up, use du
:
[ andrew@pc01 ex ]$ du 4 ./d/e/f 8 ./d/e 12 ./d 4 ./c 20 .
du
takes a --max-depth=N
flag, which only shows directories N
levels down (or fewer) from the specified directory:
[ andrew@pc01 ex ]$ du -h --max-depth=1 12K ./d 4.0K ./c 20K .
ps
shows all of the user's currently-running processes (aka. jobs):
[ andrew@pc01 ex ]$ ps PID TTY TIME CMD 16642 pts/15 00:00:00 ps 25409 pts/15 00:00:00 bash
passwd / logout / exit
Change your account password with passwd
. It will ask for your current password for verification, then ask you to enter the new password twice, so you don't make any typos:
[ andrew@pc01 dir ]$ passwd Changing password for andrew. (current) UNIX password: <type current password> Enter new UNIX password: <type new password> Retype new UNIX password: <type new password again> passwd: password updated successfully
logout
exits a shell you’ve logged in to (where you have a user account):
[ andrew@pc01 dir ]$ logout ────────────────────────────────────────────────────────────────────────────── Session stopped - Press <return> to exit tab - Press R to restart session - Press S to save terminal output to file
exit
exits any kind of shell:
[ andrew@pc01 ~ ]$ exit logout ────────────────────────────────────────────────────────────────────────────── Session stopped - Press <return> to exit tab - Press R to restart session - Press S to save terminal output to file
clear / *
Run clear
to move the current terminal line to the top of the screen. This command just adds blank lines below the current prompt line. It's good for clearing your workspace.
Use the glob (*
, aka. Kleene Star, aka. wildcard) when looking for files. Notice the difference between the following two commands: