Skip to content

Reference

Linux and shell commands, with examples

The 73 commands that cover most everyday work in a Linux terminal, grouped by what you are trying to do. Each has a plain-English explanation, commands you can copy, the flags worth knowing, and a warning wherever a command can delete, overwrite or lock you out of something. Where macOS behaves differently, the entry says so.

Nothing runs on this page, and there is deliberately no pretend terminal: a real shell needs a real operating system underneath it. Type these into your own terminal instead (on Windows, WSL or Git Bash; on macOS, the Terminal app). New to the shell? The Linux command line concept guide and the Bash guide explain the ideas first, and the Git commands reference covers version control.

Moving around and managing files

Everything on a Linux system sits in one tree of folders that starts at /. These commands tell you where you are, move you around that tree, and create, copy, move, link, find, and delete files.

pwd

Prints the full path of the folder you are currently working in.

Your shell always has a current directory, and relative paths such as notes.txt or ../logs are measured from it, so pwd is the quickest way to get your bearings after a few cd commands. If you arrived through a symbolic link, plain pwd usually shows the path through the link, while pwd -P shows where you really are on disk.

Shell
pwd

Show the directory you are in.

Shell
pwd -P

Show the real location with any symbolic links resolved.

-P
Resolve symbolic links and print the physical path.

ls

Lists the files and folders inside a directory.

With no argument it lists the current folder. Names that start with a dot, such as .env or .gitignore, stay hidden unless you add -a, and flags can be combined, so ls -lah gives a detailed, readable listing that includes them. The tree command, which draws folders as a nested diagram, is not installed by default on most distributions, so you would have to add it with your package manager first.

Shell
ls

List the current folder.

Shell
ls -la

Long listing with permissions, owner, size, and date, hidden files included.

Shell
ls -lh project/

Show sizes as K, M, or G instead of raw bytes.

Shell
ls -lt

Newest changes first, handy for spotting the file you just edited.

-l
Long format: one entry per line with permissions, owner, size, and modification time.
-a
Include hidden entries whose names begin with a dot.
-h
With -l, print sizes in readable units such as 4.0K or 12M.
-t
Sort by modification time, newest first.

cd <directory>

Changes the directory your shell is working in.

Plain cd or cd ~ takes you home, .. means the parent folder, and cd - jumps back to wherever you were before and prints that path, which makes flipping between two places easy. cd has to be built into the shell, because a separate program cannot change the folder of the shell that started it; for the same reason, a script that calls cd leaves your terminal where it was unless you source the script.

Shell
cd project

Move into the project folder inside the current one.

Shell
cd ..

Go up one level.

Shell
cd ~

Return to your home folder; plain cd does the same.

Shell
cd -

Switch back to the folder you were in before.

mkdir -p <path>

Creates new directories, including any missing parent folders when you add -p.

Without -p, mkdir fails if a parent in the path does not exist yet or if the folder is already there. With -p it builds the whole chain and quietly succeeds when the folder already exists, which is why scripts nearly always use it.

Shell
mkdir drafts

Create one folder in the current directory.

Shell
mkdir notes drafts archive

Create several folders at once.

Shell
mkdir -p project/src/components

Create the full path, making project and src along the way if needed.

-p
Create missing parent folders and do not complain if the target already exists.
-v
Print a line for every folder that gets created.

touch <file>

Creates an empty file if it does not exist, or updates the modification time of one that does.

It never changes what is inside an existing file, so it is safe to run on something you care about. People mostly use it to create placeholder files quickly, or to bump a timestamp so a build tool treats a file as changed.

Shell
touch notes.txt

Create an empty notes.txt, or refresh its timestamp if it exists.

Shell
touch index.html style.css app.js

Create several empty files in one go.

-c
Only update files that already exist; never create new ones.

cp <source> <destination>

Copies files, and whole folders when you add -r.

If the destination is an existing folder the copy goes inside it; otherwise the copy takes the destination name. Because of that rule, running the same cp -r twice nests the folder on the second run, leaving you with project-copy/project.

Careful: When a file already exists at the destination, cp replaces its contents without asking and keeps no copy of the old version. Add -i if you want to be prompted first.

Shell
cp notes.txt notes-backup.txt

Make a copy next to the original under a new name.

Shell
cp notes.txt todo.txt archive/

Copy several files into an existing folder.

Shell
cp -r project project-copy

Copy a folder and everything in it; project-copy is created if it does not exist.

Shell
cp -i draft.txt notes.txt

Ask before replacing notes.txt if it already exists.

-r
Copy directories and everything inside them.
-i
Prompt before overwriting an existing file.
-p
Keep the original permissions and timestamps on the copy.
-v
Print each file as it is copied.

mv <source> <destination>

Moves files or folders to a new place, which is also how you rename them.

Renaming is simply a move to a new name in the same folder, so there is no separate step for it. A move within the same filesystem is instant even for huge folders, because only the directory entry changes, and folders need no -r flag.

Careful: If something already exists at the destination name, mv replaces it silently and the replaced file cannot be recovered. Use -i to be asked or -n to leave existing files alone.

Shell
mv draft.txt notes.txt

Rename draft.txt to notes.txt.

Shell
mv notes.txt archive/

Move a file into the archive folder, keeping its name.

Shell
mv old-name/ new-name/

Rename a folder; no recursive flag is needed.

Shell
mv -n report.txt archive/

Move the file only if archive/ has no file of that name yet.

-i
Ask before overwriting an existing file.
-n
Never overwrite an existing file.
-v
Report each move as it happens.

rm <file>

Deletes files, and with -r deletes folders along with everything inside them.

rm will not delete a folder unless you give -r, and -f silences both prompts and complaints about missing paths, which is why rm -rf is common in scripts. Wildcards are expanded by the shell before rm even runs, so run ls with the same pattern first to see exactly what would go.

Careful: There is no trash on the command line: removed files are gone and ordinary tools cannot bring them back. rm -rf never asks for confirmation, so a small typo does a lot of damage; rm -rf * .log, with a stray space, deletes everything in the folder rather than just the log files.

Shell
rm notes-backup.txt

Delete a single file.

Shell
rm -i *.log

Ask about each matching file before deleting it.

Shell
rm -r old-project/

Delete a folder and all of its contents, prompting only for write-protected files.

Shell
rm -rf build/

Force-delete a build folder with no prompts and no error if it is already gone.

-r
Remove directories and everything beneath them.
-f
Never prompt, and ignore paths that do not exist.
-i
Confirm every single removal.
-I
Ask once when deleting more than three files or when recursing; less tedious than -i.

find <where> <tests>

Searches a folder tree for files by name, type, age, and more, and can run a command on each result.

find walks every subfolder of the starting point and prints each match. Quote wildcard patterns such as "*.txt" so the shell hands them to find instead of expanding them itself. With -exec, {} stands for each path found: ending with \; runs the command once per file, while ending with + passes many paths per run and is much faster.

Shell
find . -name "*.txt"

Every .txt file under the current folder; -iname ignores letter case.

Shell
find . -type d -name node_modules

Find folders, not files, called node_modules.

Shell
find . -type f -mtime -7

Files modified within the last seven days.

Shell
find src -name "*.ts" -exec grep -l "TODO" {} +

List the TypeScript files that contain TODO.

-name <pattern>
Match the file name against a wildcard pattern, case sensitively.
-type f|d
Keep only regular files (f) or directories (d).
-mtime <days>
Filter by days since the last change: -7 means within a week, +30 means older than 30 days.
-exec <cmd> {} +
Run a command on the results, with {} replaced by the paths.

Reading files

Look inside files without opening an editor. Use cat for short files, less for long ones, and head or tail when only the beginning or the end matters.

cat <file>

Prints the whole contents of one or more files to the terminal.

It suits short files; for anything longer than a screen, less is easier because cat pours everything out at once. The name is short for concatenate, and joining several files into one is its other everyday job.

Shell
cat notes.txt

Print a file.

Shell
cat part1.txt part2.txt > combined.txt

Join two files, in order, into a new file.

Shell
cat -n data.csv

Show the file with line numbers.

Shell
cat -A windows.txt

Reveal invisible characters: tabs show as ^I, Windows line endings as ^M, and each line end as $.

-n
Number every output line.
-A
Show tabs, line endings, and other invisible characters. This is GNU-only; cat -et is the closest option on macOS.

less <file>

Opens a file in a scrollable viewer so you can page through and search it.

less opens instantly even on very large logs because it only reads what it needs to show. Inside it, Space and b move a page forward and back, /word searches, n jumps to the next match, g and G go to the start and end, and q quits. Tools such as man and git log display their output through less, so the same keys work there too.

Shell
less server.log

Browse a log file page by page.

Shell
less -N server.log

Show line numbers down the left edge.

Shell
less +F server.log

Follow new lines as they arrive; Ctrl+C stops following and q quits.

Shell
ps aux | less

Page through the output of another command.

-N
Display line numbers.
-S
Cut long lines off at the screen edge instead of wrapping them.
-i
Make searches ignore case unless the pattern contains capital letters.

tail <file>

Shows the last lines of a file, and with -f keeps printing new lines as they are written.

tail -f is the standard way to watch a log while you reproduce a problem; Ctrl+C stops watching without affecting the program that writes the log. Logs are often rotated, meaning renamed and replaced by a fresh file, and -F copes with that by reopening the file by name, whereas -f keeps following the old renamed copy.

Shell
tail notes.txt

The last ten lines.

Shell
tail -n 50 app.log

The last 50 lines.

Shell
tail -f app.log

Print the end of the log and keep streaming new lines.

Shell
tail -n +2 data.csv

Everything from line 2 onward, a quick way to drop a header row.

-n <count>
How many lines to show; a leading + means start at that line number.
-f
Keep the file open and print lines as they are appended.
-F
Like -f, but reopen the file if it is replaced, as happens with log rotation.

wc <file>

Counts the lines, words, and bytes in a file or in piped input.

Plain wc prints all three counts followed by the file name, but input that arrives through a pipe or < has no name to print, so wc -l < file gives just the number. wc -l actually counts newline characters, which means a final line with no newline at the end is not counted.

Shell
wc -l app.log

Number of lines, followed by the file name.

Shell
wc -l < app.log

Just the number, with no file name.

Shell
grep "ERROR" app.log | wc -l

Count how many lines mention ERROR.

Shell
ls | wc -l

Roughly how many visible entries a folder holds.

-l
Count lines.
-w
Count words, meaning runs of characters separated by spaces.
-c
Count bytes.
-m
Count characters, which differs from bytes for accented letters, emoji, and other non-ASCII text.

Searching and transforming text

Small tools that each do one job on lines of text: find matching lines, sort them, count them, cut out columns, or rewrite them. Chained together with pipes they cover a surprising amount of everyday data work.

grep <pattern> <file>

Prints the lines that match a pattern, from files or from piped input.

The pattern is a regular expression, so characters like . * [ and ^ have special meanings; add -F when you want to search for that text literally. With -r it searches every file under a folder, the classic way to find where something is used in a codebase. grep exits with status 0 when it finds a match and 1 when it does not, so it also works as a test in if statements and && chains.

Shell
grep "ERROR" app.log

Lines containing ERROR, matched case sensitively.

Shell
grep -rn "TODO" src/

Search every file under src, showing file names and line numbers.

Shell
grep -v "^#" config.ini

Hide the comment lines that start with #.

Shell
grep -iE "warn|error" app.log

Lines mentioning warn or error in any case; -E enables the | alternative.

-i
Ignore the difference between upper and lower case.
-r
Search all files beneath the given folders.
-n
Prefix each matching line with its line number.
-v
Invert the match and print the lines that do not match.

sort <file>

Sorts lines alphabetically, numerically, or by a chosen column.

By default sort compares text, so 100 comes before 9; add -n to compare numbers by value. Redirecting the result back into the same file with > empties that file before sort can read it, so use -o with the same name when you want to sort a file in place.

Shell
sort names.txt

Alphabetical order.

Shell
sort -n scores.txt

Numeric order, smallest first; add -r to reverse it.

Shell
sort -t, -k3 -n data.csv

Sort comma-separated rows by the number in their third column.

Shell
sort -o names.txt names.txt

Sort a file and save the result over the original safely.

-n
Compare values as numbers.
-r
Reverse the order.
-k <field>
Sort by a particular field; -t sets the separator, which is otherwise any whitespace.
-h
Understand sizes such as 200K, 30M, and 1.5G, as printed by du -h.

uniq

Collapses repeated lines into one, and can count or list the duplicates.

uniq only compares each line with the one directly above it, so duplicates that are not next to each other slip through, which is why it almost always follows sort. The chain sort | uniq -c | sort -rn is a quick way to rank the most common lines in any file.

Shell
sort visitors.txt | uniq

Remove duplicates; sort -u does the same in one step.

Shell
sort visitors.txt | uniq -c | sort -rn

Count each distinct line and list the most frequent first.

Shell
sort emails.txt | uniq -d

Show only lines that appear more than once.

-c
Prefix each line with the number of times it occurred.
-d
Print only lines that were repeated.
-u
Print only lines that were never repeated.
-i
Ignore case when comparing neighbouring lines.

cut -d <delimiter> -f <fields>

Pulls selected columns or character ranges out of each line.

cut works well on simple data where columns are separated by exactly one character, and its default separator is a tab. It does not understand quoted CSV values that contain commas, and several spaces in a row count as several empty columns, so awk is the better fit for space-aligned command output.

Shell
cut -d, -f1 data.csv

The first column of a comma-separated file.

Shell
cut -d, -f1,3 data.csv

Columns one and three.

Shell
cut -d: -f1 /etc/passwd

The name of every account on the system.

Shell
cut -c1-8 app.log

The first eight characters of each line.

-d <char>
The single character between fields; a tab if you leave it out.
-f <list>
Which fields to keep, such as 2, 1,3, or 2-4.
-c <range>
Select characters by position instead of fields.

tr <set1> <set2>

Translates, squeezes, or deletes individual characters in a stream of text.

tr reads only standard input, so give it data through a pipe or <; it does not take a file name. It works one character at a time rather than on words, so reach for sed when you need to replace whole strings.

Shell
echo "hello world" | tr 'a-z' 'A-Z'

Convert text to upper case.

Shell
tr -d '\r' < windows.txt > unix.txt

Strip Windows carriage returns so the copy has Linux line endings.

Shell
echo "a,b,c" | tr ',' '\n'

Put each comma-separated item on its own line.

Shell
echo "too    many   spaces" | tr -s ' '

Squeeze runs of spaces down to one.

-d
Delete the listed characters.
-s
Squeeze each run of a repeated character into a single one.

sed 's/old/new/g' <file>

Edits text as a stream, most often to find and replace, and prints the result without touching the file unless you add -i.

In s/old/new/ only the first match on each line changes; the trailing g changes every match, and for text full of slashes, such as URLs, you can pick another separator like s|old|new|. The -i flag edits the file itself, and platforms disagree on its syntax: GNU sed on Linux accepts -i alone, the BSD sed on macOS needs a backup suffix and uses -i '' for none, and -i.bak with the suffix attached works on both.

Careful: sed -i rewrites the file with no undo. If the pattern matches more than you expected, the original text is gone unless you used a backup suffix or the file is under version control, so preview the output without -i first.

Shell
sed 's/http:/https:/g' config.txt

Print the file with every http: changed to https:; the file itself stays as it was.

Shell
sed -i 's/http:/https:/g' config.txt

Make that change inside the file (GNU sed).

Shell
sed -i.bak 's/http:/https:/g' config.txt

Edit in place and keep the original as config.txt.bak.

Shell
sed -n '5,10p' app.log

Print only lines 5 to 10.

-i
Write the changes back into the file instead of printing them.
-n
Print nothing unless a command such as p asks for it.
-E
Use extended regular expressions, so +, ?, | and ( ) need no backslashes.

awk '{print $1}' <file>

Splits each line into fields and lets you print, filter, or total them with a tiny program.

Fields are numbered $1, $2, and so on, $0 is the whole line, and NR is the current line number. By default any run of spaces or tabs separates fields, which makes awk a better fit than cut for aligned output, and -F chooses a different separator. Keep the program in single quotes so the shell does not swap $1 for one of its own variables.

Shell
awk '{print $1}' access.log

The first field of each line, such as the client address in a web log.

Shell
awk -F, 'NR > 1 {print $1, $3}' data.csv

Columns one and three of a CSV, skipping the header row.

Shell
awk '$2 > 100' sales.txt

Only the lines whose second field is greater than 100.

Shell
awk '{sum += $2} END {print sum}' sales.txt

Add up the second column and print the total.

-F <sep>
Set the field separator, for example -F, for commas or -F: for colons.
-v name=value
Pass a value in from the shell as an awk variable.

xargs <command>

Reads items from standard input and turns them into arguments for another command.

Commands such as mkdir, touch, and rm take names as arguments and ignore piped input, and xargs bridges that gap. It splits input on spaces as well as newlines, so a name like my notes.md becomes two arguments unless you pair find -print0 with xargs -0. GNU xargs still runs the command once when the input is empty; -r prevents that, and the BSD xargs on macOS already skips empty input.

Shell
find . -name "*.md" -print0 | xargs -0 grep -l "draft"

Search Markdown files for draft, safely handling names that contain spaces.

Shell
xargs mkdir -p < folders.txt

Create every folder listed in a text file.

Shell
echo "one two three" | xargs -n 1 echo

Run the command once per item instead of once for all.

Shell
printf '%s\n' api web worker | xargs -I {} mkdir -p services/{}/logs

Insert each item wherever {} appears in the command.

-0
Expect items separated by null characters, as produced by find -print0.
-n <count>
Pass at most this many items to each run of the command.
-I {}
Run once per input line, substituting the line wherever {} appears.
-r
GNU only: skip running the command when there is no input.

Pipes and redirection

Every command has three standard streams: input (0), normal output (1), and error output (2). These operators connect those streams to files or to other commands. The shell handles them, so they work the same way with any program.

command1 | command2

Sends the normal output of one command straight into the input of the next.

Pipes let you build up a result step by step without temporary files. Only standard output travels through the pipe, so error messages still reach your screen unless you redirect them too. A pipeline reports the exit status of its last command, so scripts often run set -o pipefail to stop an earlier failure from being hidden.

Shell
ls -l | less

Scroll through a long listing.

Shell
grep "ERROR" app.log | wc -l

Count the error lines.

Shell
history | grep ssh

Find ssh commands you ran earlier.

Shell
cut -d, -f2 data.csv | sort | uniq -c

Count how many rows share each value in column two.

command > file

Writes a command's normal output into a file, replacing whatever the file held before.

The shell creates the file if needed and empties it before the command even starts, which is why sort notes.txt > notes.txt leaves you with an empty file. Running set -o noclobber makes > refuse to overwrite existing files for the rest of the session, and >| then overrides that when you really mean it.

Careful: > wipes the current contents of the target without asking, and pointing it at the same file a command is reading destroys that file's data. Check the name, or use >> if you meant to add to the end.

Shell
ls > files.txt

Save a folder listing in files.txt.

Shell
echo "draft" > notes.txt

Replace everything in notes.txt with one line.

Shell
sort names.txt > sorted-names.txt

Send sorted output to a different file and leave the original intact.

Shell
set -o noclobber

Protect existing files from accidental > overwrites in this shell.

command >> file

Adds a command's output to the end of a file, keeping what is already there.

Like >, it creates the file when it is missing. It is the usual choice for log files and for adding lines to settings files. Running the same >> command twice adds the text twice, so scripts that append settings should check for the line first.

Shell
echo "Buy milk" >> todo.txt

Add a line to the end of todo.txt.

Shell
date >> run.log

Record a timestamp each time a job runs.

Shell
./backup.sh >> backup.log 2>&1

Append both normal output and errors to a running log.

Shell
grep -qxF "cache=on" settings.conf || echo "cache=on" >> settings.conf

Add the line only if the file does not contain it yet.

command 2> file

Sends a command's error messages to a file, apart from its normal output.

Programs write problems to a separate stream, number 2, which is why error text still appears on screen after you redirect output with >. Sending the two streams to different files gives you a tidy record of what went wrong, and 2>> appends errors instead of overwriting them.

Shell
ls missing-folder 2> errors.txt

The error message lands in errors.txt instead of on screen.

Shell
./build.sh > build.log 2> build-errors.log

Normal output and errors go to two different files.

Shell
find / -name "*.conf" 2> /dev/null

Search the whole system while hiding the permission-denied messages.

command > file 2>&1

Merges error messages into the same destination as normal output.

2>&1 means send stream 2 wherever stream 1 points at that moment, so order matters: > file 2>&1 captures both, while 2>&1 > file leaves errors on the screen because output had not moved to the file yet. Bash also accepts &> file as a shortcut, but a script run by plain sh reads that differently, so the long form is safer there.

Shell
./build.sh > build.log 2>&1

Capture everything the build prints in one file.

Shell
./build.sh 2>&1 | grep -i warning

Search errors and normal output together.

Shell
./build.sh &> build.log

The bash shorthand for sending both streams to a file.

command < file

Feeds a file into a command's standard input, as though you had typed its contents.

Most tools accept a file name directly, but a few, such as tr, only read input, and with others the output changes slightly: wc -l < file prints the count without the name. A related form, the here-document written as << followed by a marker word, supplies several lines of input straight from a script.

Shell
wc -l < names.txt

Print just the line count.

Shell
tr 'a-z' 'A-Z' < notes.txt

Give tr a file to read, since it does not accept file names.

Shell
sort < names.txt > sorted-names.txt

Read from one file and write the result to another.

command | tee <file>

Shows output on screen and saves a copy to a file at the same time.

Use it to watch a long command while keeping a log. It also fixes a common sudo surprise: in sudo echo text > /etc/file the redirection is done by your own unprivileged shell and fails, whereas echo text | sudo tee /etc/file writes the file with root rights.

Shell
./build.sh | tee build.log

Watch the build and save its output to build.log.

Shell
./build.sh 2>&1 | tee build.log

Include error messages in the saved copy as well.

Shell
echo "line" | tee -a notes.txt

Append to the file instead of replacing it.

Shell
echo "debug=true" | sudo tee -a /etc/myapp.conf > /dev/null

Append to a root-owned file without echoing the text back to the screen.

-a
Append to the file rather than overwriting it.

/dev/null

A special file that throws away anything written to it and always reads as empty.

Redirect output there when you only care whether a command worked, not what it printed. Because reading it gives nothing, it also serves as blank input for a command that would otherwise sit waiting for you to type.

Shell
find / -name "*.conf" 2>/dev/null

Hide the error messages but keep the results.

Shell
./backup.sh > /dev/null 2>&1

Silence a command completely.

Shell
curl -s -o /dev/null -w "%{http_code}\n" https://example.com

Discard the page body and print only the HTTP status code.

Permissions and users

Every file has an owner, a group, and three sets of permissions that decide who may read it, change it, or run it. These commands show those settings, change them, and tell you which account you are using.

ls -l

Shows each file's permission string, such as -rwxr-xr--, alongside its owner and group.

The first character is the type: - for a regular file, d for a directory, l for a symbolic link. The next nine characters are three sets of three, for the owner, the group, and everyone else, each showing r (read), w (write), and x (execute, or enter for a folder), with - wherever a permission is missing. In numbers r is 4, w is 2, and x is 1, so rwx is 7, r-x is 5, and -rwxr-xr-- as a whole is 754.

Shell
ls -l deploy.sh

Permissions, link count, owner, group, size, date, and name for one file.

Shell
ls -ld project/

Details of the folder itself rather than its contents.

Shell
stat -c '%a %A %n' deploy.sh

Numeric and symbolic permissions side by side; this -c form is GNU-specific.

chmod <mode> <file>

Changes who is allowed to read, write, or execute a file or folder.

Symbolic modes adjust what is already set: u, g, o, and a pick the owner, group, others, or all, and +, -, or = add, remove, or set exactly. Numeric modes set all nine bits at once with one digit each for owner, group, and others, so 644 is typical for ordinary files and 755 for scripts and folders. SSH refuses to use a private key that other users can read, which is why key files need 600.

Careful: chmod -R 777 lets every account on the machine modify or replace every file in that tree and marks plain files as executable. It can appear to fix a permission error while opening a security hole, so work out which user actually needs access and grant only that.

Shell
chmod +x deploy.sh

Make a script runnable, so ./deploy.sh works.

Shell
chmod 644 notes.txt

The owner can read and write; everyone else can only read.

Shell
chmod u+x,go-w deploy.sh

Let the owner execute, and take write access away from group and others.

Shell
chmod 600 ~/.ssh/id_ed25519

Restrict a private key to its owner, as SSH expects.

-R
Apply the change to a folder and everything inside it.
u / g / o / a
Target the owner, the group, other users, or all three.
+ / - / =
Add, remove, or set exactly the permissions that follow.

chown <user>:<group> <file>

Changes which user and group own a file or folder.

Handing a file to another user normally requires root, so chown usually runs under sudo. You can change only the owner (user), both (user:group), or only the group (:group). A frequent use is giving a web app's folder to the account the web server runs as.

Careful: Running chown -R on system folders such as /usr or /etc can break sudo, SSH logins, and installed services, which expect particular owners on particular files. Changing ownership also clears the setuid bit that programs like sudo rely on, so point chown -R only at folders that belong to your own project.

Shell
sudo chown deploy notes.txt

Make the user deploy the owner of the file.

Shell
sudo chown -R www-data:www-data /var/www/example

Give a site's folder and its contents to the web server account used on Debian and Ubuntu.

Shell
sudo chown :developers shared-report.txt

Change only the group.

Shell
sudo chown -R "$USER":"$USER" project/

Take back a project folder that was accidentally created with sudo.

-R
Apply the change to a folder and everything below it.

sudo <command>

Runs a single command with administrator (root) privileges.

sudo asks for your own password, not root's, and usually remembers it for a few minutes. Your account has to be allowed to use it, typically through the sudo group on Debian and Ubuntu or the wheel group on Fedora and RHEL. Redirections such as > are carried out by your shell before sudo starts, so to write a protected file, pipe into sudo tee instead.

Careful: A command run with sudo can change or delete any file on the system, including those needed to boot or log in. Do not paste sudo commands you do not understand, and avoid using sudo just to get past a permission error with tools like npm or pip, since that leaves root-owned files in folders you normally write to.

Shell
sudo apt update

Run one command as root.

Shell
sudo !!

Repeat the previous command with sudo in front after it failed on permissions.

Shell
sudo -u postgres psql

Run a command as another user instead of root.

Shell
sudo -l

List what your account is allowed to run with sudo on this machine.

-u <user>
Run the command as this user rather than root.
-i
Open an interactive root shell; type exit to leave it.
-l
Show which commands your account may run.

whoami / id

whoami prints the name of the account you are using, and id adds your numeric user ID and every group you belong to.

Both are quick sanity checks after sudo -i, su, or logging in to a server, when it is easy to lose track of which account you are on. Groups control access to things such as Docker, serial devices, and shared folders, and a group you were just added to only appears in id after you log out and back in.

Shell
whoami

Print your username.

Shell
sudo whoami

Confirm sudo works for you; the answer should be root.

Shell
id

Your user ID, primary group, and all other groups.

Shell
id -Gn

Just the names of your groups; the groups command prints the same list.

-u
With id, print only the user ID.
-G
With id, print every group ID.
-n
With -u or -G, print names instead of numbers.

Processes and jobs

A process is a running program, and each one has a numeric process ID, or PID. These commands list what is running, stop things that misbehave, and move work into the background so you can keep using the terminal.

ps aux

Lists running processes with their owner, PID, CPU and memory use, and full command.

ps takes a one-time snapshot; top gives a live view. The aux form comes from the BSD tradition and is written without a dash, while ps -ef is the System V style that shows much the same information plus each parent's PID. When you search with ps aux | grep, the grep process itself often shows up in the results, and pgrep avoids that.

Shell
ps aux

Every process on the system.

Shell
ps aux | grep nginx

Find processes whose command line mentions nginx.

Shell
pgrep -a node

PIDs and command lines of processes named node; -a means something else on macOS, where pgrep -lf does this.

Shell
ps aux --sort=-%mem | head

The processes using the most memory (Linux procps ps).

a
Include processes that belong to other users.
u
Use the user-oriented layout with %CPU, %MEM, and start time columns.
x
Include processes with no terminal, such as background services.

top

Shows a live, refreshing view of the processes using the most CPU and memory.

The header summarises uptime, load, and memory, and the list below updates every few seconds. While it runs, P sorts by CPU, M sorts by memory, k sends a signal to a PID you type, and q quits. htop is a friendlier alternative that usually needs installing, and the top on macOS uses different keys and options, such as top -o cpu.

Shell
top

Open the live process view.

Shell
top -u deploy

Show only processes owned by the user deploy.

Shell
top -b -n 1 | head -n 20

Print a single plain-text snapshot, useful for saving or pasting into a report.

-u <user>
Limit the list to one user's processes.
-d <seconds>
Change how often the display refreshes.
-b
Batch mode: print plain text instead of the interactive screen.

kill <pid>

Sends a signal to a process, by default asking it to shut down cleanly.

Plain kill sends SIGTERM, which a well-behaved program handles by finishing its work, closing connections, and exiting. If it ignores that, kill -9 sends SIGKILL, which cannot be caught and ends the process on the spot. pkill and killall choose processes by name instead of PID, so check what they will match before running them.

Careful: kill -9 gives the program no chance to clean up: temporary and lock files stay behind, buffered data never reaches disk, and a database may need recovery on its next start. Try plain kill first and give it a few seconds before using -9.

Shell
kill 4821

Ask process 4821 to exit.

Shell
kill -9 4821

Force it to stop immediately if it did not respond.

Shell
pkill -f "node server.js"

Signal every process whose full command line contains node server.js.

Shell
kill -l

List the signal names and their numbers.

-TERM (15)
The default, a polite request to shut down.
-KILL (9)
End the process immediately; it cannot refuse or clean up.
-HUP (1)
Many services treat this as a request to reload their configuration; check the program's documentation.
-l
List the available signals.

command &

Starts a command in the background so your prompt comes back straight away.

The shell prints a job number in brackets and the process ID, and $! holds that PID afterwards. A background job still writes to your terminal unless you redirect its output, and it is usually ended when the terminal window closes, so use nohup or a proper service for anything that must keep running.

Shell
sleep 300 &

Run a long command in the background and get your prompt back.

Shell
./export-data.sh > export.log 2>&1 &

Run a script in the background with all of its output going to a log.

Shell
echo $!

Print the PID of the most recent background command.

Shell
wait

Pause until all background jobs have finished, useful in scripts.

jobs / fg / bg

jobs lists the background and stopped jobs in your shell, fg brings one back to the front, and bg lets a stopped one carry on in the background.

Each job gets a small number such as [1], which you refer to as %1 with fg, bg, or kill. A common move is to press Ctrl+Z to pause a program that has taken over the terminal, then type bg so it keeps running out of the way, or fg to return to it. Without a number both act on the current job, marked + in the jobs list, and jobs only knows about work started from this terminal, so use ps to see everything else.

Shell
jobs -l

List jobs with their state and process IDs.

Shell
fg %2

Bring job 2 back to the foreground.

Shell
bg

Resume the most recently stopped job in the background.

Shell
kill %1

End job 1 without looking up its PID.

-l
With jobs, also show each job's process ID.

Ctrl+C / Ctrl+Z

Ctrl+C interrupts the program running in the foreground, and Ctrl+Z pauses it.

Ctrl+C sends SIGINT, which most programs take as a request to stop now. Ctrl+Z sends SIGTSTP, which suspends the program without ending it, so it keeps its memory and open files until you resume it with fg or bg or end it with kill. Ctrl+D is not a signal at all; it marks the end of input, which is why it closes a shell or an interactive prompt such as python.

Shell
sleep 300

Start something that runs for a while, then press Ctrl+C to end it or Ctrl+Z to pause it.

Shell
jobs

After Ctrl+Z, confirm the program is listed as Stopped.

Shell
fg

Resume the paused program in the foreground.

nohup <command> &

Runs a command that keeps going after you log out or close the terminal.

nohup makes the command ignore the hang-up signal sent when a session ends, and if its output would otherwise go to the terminal it is saved in a file called nohup.out. That is fine for one-off jobs, but tmux or screen let you reattach to a session later, and a systemd service is the right home for something that should always be running.

Shell
nohup ./backup.sh &

Keep the script running after you disconnect; output goes to nohup.out.

Shell
nohup ./backup.sh > backup.log 2>&1 &

Choose your own log file instead.

Shell
disown %1

Detach a job you already started so closing the terminal does not end it.

Disk, memory, and system info

Quick health checks for a machine: how full the disks are, what is using the space, how much memory is left, and what system you are actually running.

df -h

Shows how much space is used and available on each mounted filesystem.

It is the first thing to check when commands start failing with No space left on device. Give it a path to see only the filesystem that path lives on. A disk can also run out of inodes, the entries used for each file, while still showing free space, and df -i reveals that.

Shell
df -h

All filesystems with sizes in G and M.

Shell
df -h .

Only the filesystem that holds the current folder.

Shell
df -i

Inode usage instead of bytes.

Shell
df -hT

Add a column with each filesystem's type, such as ext4 or tmpfs (GNU only).

-h
Print sizes in readable units.
-i
Report inodes rather than bytes.
-T
Show the filesystem type (GNU df).

du -sh <path>

Reports how much disk space files and folders take up.

df tells you a disk is full and du tells you what filled it. Without -s it prints a line for every subfolder, which is usually far too much, so use -s or a depth limit and pipe the result into sort -h to find the biggest items. The -d depth option works on both GNU/Linux and macOS.

Shell
du -sh project/

The total size of one folder.

Shell
du -sh *

The size of each item in the current folder.

Shell
du -h -d 1 | sort -h

Each subfolder's size, with the largest at the bottom.

Shell
du -shc *.log

The size of each log file plus a grand total.

-s
Print only a total for each argument.
-h
Print sizes in readable units.
-d <depth>
List folders only down to this many levels.
-c
Add a grand total line at the end.

free -h

Shows how much memory and swap is in use on a Linux machine.

Look at the available column rather than free: Linux deliberately fills spare memory with disk cache and hands it back the moment programs need it, so a small free figure is normal. Low available memory combined with heavy swap use is the real sign of a RAM shortage. free comes with Linux's procps tools and does not exist on macOS, where vm_stat or Activity Monitor fill the same role.

Shell
free -h

Memory and swap in readable units.

Shell
free -m

The same figures in mebibytes.

Shell
free -h -s 5

Print a fresh report every five seconds until you press Ctrl+C.

-h
Print sizes in readable units.
-s <seconds>
Repeat the report at this interval.

uname -a

Prints details about the kernel and hardware, such as the kernel version and CPU architecture.

uname describes the kernel rather than the distribution, so to learn whether you are on Ubuntu or Fedora, and which release, read /etc/os-release. The architecture from uname -m matters when downloading prebuilt programs, because x86_64 and aarch64 builds are not interchangeable.

Shell
uname -a

Everything uname knows, on one line.

Shell
uname -r

Only the kernel release.

Shell
uname -m

The CPU architecture, such as x86_64 or aarch64; macOS on Apple silicon reports arm64.

Shell
cat /etc/os-release

The distribution's name and version.

-a
Print all available information.
-r
Print the kernel release.
-m
Print the machine hardware name.

uptime

Shows how long the system has been running, how many users are logged in, and the load averages.

The three load figures average, over the last 1, 5, and 15 minutes, how many processes were running, waiting for a CPU, or stuck waiting on disk. Compare them with the number of CPU cores, which nproc prints; a load that stays above the core count means work is queuing up.

Shell
uptime

A one-line summary.

Shell
uptime -p

Only the running time in words (Linux procps only).

Shell
nproc

The number of CPU cores available, to compare against the load.

Networking

Fetch web pages and APIs, check whether a host responds, log in to remote machines, copy files between them, and see which ports are open. Swap example.com and the 203.0.113.x addresses for your own hosts.

curl <url>

Sends a request to a URL and prints the response, the everyday tool for testing websites and APIs.

By default curl prints the response body and does not follow redirects, so add -L when a URL has moved. It treats HTTP error codes such as 404 as a successful transfer unless you add -f, which matters in scripts that check the exit status. It ships with nearly every Linux distribution and with macOS.

Careful: Install guides often pipe a download straight into a shell, as in curl ... | sh. That runs whatever the server sends, with your permissions or root's if sudo is involved, before you have seen a line of it. Save the script to a file, read it, and only then run it.

Shell
curl https://example.com

Print a page's HTML.

Shell
curl -I https://example.com

Fetch only the response headers, including the status code.

Shell
curl -L -o page.html https://example.com

Follow any redirects and save the body to page.html.

Shell
curl -fsSL https://example.com/install.sh -o install.sh

Download a script quietly, failing on HTTP errors, so you can read it before running it.

-I
Request the headers only.
-L
Follow redirects to the final location.
-o <file>
Save the response to a file instead of printing it.
-f
Exit with an error on HTTP failure codes rather than saving the error page.

curl -X POST <url> -d <data>

Sends data to a server with a POST request, adding headers with -H.

-d places data in the request body and already switches curl to POST, so -X POST is optional but makes the intent clear. Data sent with -d is labelled as form data unless you set a Content-Type header, so add one for JSON, or use --json on curl 7.82 and later, which sets the body and headers together. Wrap JSON in single quotes so the shell leaves the inner double quotes alone.

Shell
curl -X POST https://api.example.com/notes -H "Content-Type: application/json" -d '{"title":"Hello"}'

Create a resource by sending a JSON body.

Shell
curl -d "name=Ada&topic=linux" https://example.com/signup

Submit form-style fields; the method becomes POST automatically.

Shell
curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com/me

Add a header, taking the token from an environment variable instead of typing it out.

Shell
curl --json '{"title":"Hello"}' https://api.example.com/notes

The shorter JSON form available in curl 7.82 and newer.

-X <method>
Choose the HTTP method, such as POST, PUT, or DELETE.
-d <data>
Send data in the request body; start the value with @ to read it from a file, as in -d @body.json.
-H <header>
Add or replace a request header.
--json <data>
Send JSON with matching Content-Type and Accept headers (curl 7.82+).

wget <url>

Downloads files from the web straight to disk.

Unlike curl, wget saves to a file by default, follows redirects without being asked, and can resume an interrupted download, which suits large files. It is common on Linux servers but is not included with macOS and is missing from some minimal container images, where curl -O does a similar job.

Shell
wget https://example.com/files/backup.tar.gz

Save the file under its own name in the current folder.

Shell
wget -O latest.tar.gz https://example.com/files/backup.tar.gz

Choose the name of the saved file.

Shell
wget -c https://example.com/files/backup.tar.gz

Carry on with a partly finished download instead of starting over.

-O <file>
Write the download to this file name.
-c
Resume a partial download.
-q
Quiet mode with no progress output.

ping -c <count> <host>

Checks whether a host answers and how long each round trip takes.

On Linux and macOS ping keeps going until you press Ctrl+C, so -c sends a fixed number of packets; Windows stops after four by default and uses -n instead. No reply does not prove a machine is down, because many servers and firewalls block ping on purpose, so test the real service, for example with curl, before drawing conclusions.

Shell
ping -c 4 example.com

Send four pings and print a summary.

Shell
ping -c 3 203.0.113.10

Test a server by its IP address.

-c <count>
Stop after sending this many packets.

ssh <user>@<host>

Opens an encrypted terminal session on a remote machine, or runs one command there.

Key-based login is safer and more convenient than passwords: create a key pair once with ssh-keygen, then copy the public half to the server with ssh-copy-id. An entry in ~/.ssh/config lets you connect to a frequent host by a short name and remembers its user, port, and key. The first connection to a host asks you to confirm its fingerprint, and a later warning that the fingerprint changed deserves investigation before you continue.

Shell
ssh deploy@203.0.113.10

Log in to a server as the user deploy.

Shell
ssh -p 2222 deploy@203.0.113.10

Connect to an SSH server listening on a non-standard port.

Shell
ssh-keygen -t ed25519 -C "you@example.com"

Create a new key pair; the comment helps you recognise the key later.

Shell
ssh deploy@203.0.113.10 "df -h"

Run a single command remotely and see its output locally.

-p <port>
Connect to this port instead of 22.
-i <keyfile>
Use a specific private key.
-L <port>:<host>:<port>
Forward a local port through the connection, for example to reach a database that only listens on the server.
-v
Print debugging details, useful when a login fails.

scp <source> <destination>

Copies files between your machine and a remote one over SSH.

Remote paths are written user@host:path, and a path without a leading slash is relative to that user's home folder. scp uses your existing SSH keys and settings, but its port option is a capital -P, unlike ssh. For large or repeated transfers rsync is the better tool, since it only sends what has changed.

Shell
scp backup.tar.gz deploy@203.0.113.10:backups/

Upload a file into backups/ inside the remote user's home folder.

Shell
scp deploy@203.0.113.10:/var/log/app.log .

Download a remote file into the current folder.

Shell
scp -r project/ deploy@203.0.113.10:~/sites/

Copy a whole folder.

Shell
scp -P 2222 notes.txt deploy@203.0.113.10:~

Use a non-standard SSH port.

-r
Copy folders and their contents.
-P <port>
The SSH port; a capital P here, whereas ssh uses -p.
-i <keyfile>
Use a specific private key.

ss -tulpn

Lists network sockets, most often to see which programs are listening on which ports.

Use it when a server will not start because its port is taken, or to confirm a service is really listening. It replaces netstat, which comes from the older net-tools package and is no longer installed by default on many distributions, although netstat -tulpn gives similar output where it exists. Without sudo the process column stays blank for other users' programs, and on macOS lsof -iTCP -sTCP:LISTEN -n -P gives a comparable list.

Shell
ss -tulpn

Every listening TCP and UDP port, with numeric addresses.

Shell
sudo ss -tulpn

Include process names for services run by other users, such as root.

Shell
ss -tlnp | grep :3000

Check whether something is already using port 3000.

Shell
ss -tn state established

Current TCP connections rather than listening ports.

-t / -u
Show TCP or UDP sockets.
-l
Show only listening sockets.
-p
Show the process that owns each socket.
-n
Print numeric ports and addresses instead of looking up names.

dig <domain>

Looks up DNS records for a domain and shows exactly what the name server returned.

Use it to check whether a DNS change has taken effect or which address a name points to. dig is not always preinstalled: it comes in the dnsutils or bind9-dnsutils package on Debian and Ubuntu and in bind-utils on Fedora and RHEL. nslookup is an older, simpler lookup tool that is also available on Windows.

Shell
dig example.com

The full answer, including the address record and how long it may be cached.

Shell
dig +short example.com

Just the resulting addresses.

Shell
dig MX example.com

Mail server records instead of addresses.

Shell
nslookup example.com

A quick lookup with the older tool.

+short
Print only the answer values.
<type>
Ask for a record type such as A, AAAA, MX, TXT, or CNAME.
@<server>
Query a specific DNS server instead of your default one.

Archives and compression

Bundle many files into one and shrink them for backups or transfers. On Linux the usual format is .tar.gz, while .zip is the safest choice when sharing with people on Windows.

tar -czf <archive.tar.gz> <files>

Packs files and folders into a single compressed .tar.gz archive.

Read the letters as create, gzip, file; -f must come last in the group because the archive name has to follow it directly. The archive stores paths as you typed them, so run tar from the folder just above the one you are packing to keep those paths short. Use -j for .tar.bz2 or -J for .tar.xz, which compress more slowly but smaller.

Shell
tar -czf backup.tar.gz project/

Compress the project folder into backup.tar.gz.

Shell
tar -czvf backup.tar.gz project/

The same, listing each file as it is added.

Shell
tar -czf backup.tar.gz --exclude=node_modules project/

Leave out bulky folders that can be regenerated.

Shell
tar -czf "backup-$(date +%F).tar.gz" project/

Put today's date, in YYYY-MM-DD form, into the file name.

-c
Create a new archive.
-z
Compress it with gzip.
-f <file>
The archive's file name; keep this letter last when grouping.
-v
List files as they are processed.

tar -xzf <archive.tar.gz>

Unpacks a .tar.gz archive, and with -t lists what is inside without extracting.

Files come out into the current folder unless you pass -C with a destination, which must already exist. Listing first with -tzf shows whether the archive holds one top-level folder or will scatter files everywhere. GNU tar and the tar on macOS both detect the compression type when extracting, so tar -xf handles .tar.gz, .tar.bz2, and .tar.xz alike.

Careful: Extraction replaces existing files that have the same paths without asking, so unpacking an old backup over a working folder overwrites newer edits. Extract into an empty folder with -C, or add -k to skip files that already exist.

Shell
tar -tzf backup.tar.gz

List the contents without extracting anything.

Shell
tar -xzf backup.tar.gz

Extract into the current folder.

Shell
mkdir restore && tar -xzf backup.tar.gz -C restore/

Extract into a new, empty folder.

Shell
tar -xzf backup.tar.gz project/readme.txt

Pull out a single file by its path inside the archive.

-x
Extract files from the archive.
-t
List the archive's contents.
-C <dir>
Switch to this folder before extracting.
-k
Keep existing files instead of overwriting them.

gzip <file>

Compresses a single file into a .gz file, and gunzip turns it back into the original.

gzip replaces the original with the compressed file rather than keeping both, unless you add -k, which gzip 1.6 and later support. It only works on single files, so bundle folders with tar first. zcat, zless, and zgrep read or search a .gz file without unpacking it, which is handy for rotated logs.

Shell
gzip app.log

Compress app.log into app.log.gz, removing the original.

Shell
gzip -k app.log

Compress but keep app.log as well.

Shell
gunzip app.log.gz

Decompress back to app.log.

Shell
zgrep "ERROR" app.log.gz

Search inside a compressed log directly.

-k
Keep the original file.
-d
Decompress, the same as gunzip.
-9
Use the strongest and slowest compression.

zip -r <archive.zip> <folder>

Creates .zip archives with zip and extracts them with unzip.

Zip files open natively on Windows and macOS, which makes them the friendliest format for sharing. Without -r, zip adds only the empty folder entry and none of its contents. Neither tool is guaranteed on a fresh server, so install them with sudo apt install zip unzip or sudo dnf install zip unzip.

Shell
zip -r project.zip project/

Compress a folder and everything in it.

Shell
zip -r project.zip project/ -x "project/node_modules/*"

Leave the node_modules folder out of the archive.

Shell
unzip -l project.zip

List the contents without extracting.

Shell
unzip project.zip -d restore/

Extract into the restore folder, creating it if needed.

-r
With zip, include folders and everything inside them.
-x <pattern>
With zip, skip files that match the pattern.
-l
With unzip, list the archive instead of extracting it.
-d <dir>
With unzip, extract into this folder.

Environment and the shell

The shell is the program that reads your commands, usually bash on Linux. These commands print and set variables, control where programs are found, save shortcuts, and combine commands on one line. macOS uses zsh by default, which behaves the same way for nearly everything here.

echo <text>

Prints text, or the value of variables, to the terminal.

Inside double quotes the shell swaps variables such as $HOME for their values before echo sees them, while single quotes keep the text exactly as written. Options like -n and -e are not treated the same way by every shell, so scripts that need exact formatting are better served by printf.

Shell
echo "Hello, $USER"

Print a greeting with your username filled in.

Shell
echo 'Cost: $5'

Single quotes stop $5 from being read as a variable.

Shell
echo $?

Show the exit status of the previous command; 0 means success.

Shell
printf "%s\n" "Done"

The more predictable choice inside scripts.

-n
Leave out the newline at the end.
-e
In bash, interpret escapes such as \t and \n.

export NAME=value

Sets an environment variable that programs started from this shell can read.

A variable set without export exists only inside the current shell, while an exported one is handed to every command you run afterwards; either way it disappears when the terminal closes, so lasting settings belong in ~/.bashrc. There must be no spaces around the equals sign. To set a variable for just one command, write the assignment directly in front of that command.

Shell
export API_URL="https://api.example.com"

Make API_URL available to programs you start from this shell.

Shell
NODE_ENV=production node server.js

Set a variable for this one command only.

Shell
unset API_URL

Remove the variable again.

env

Lists every environment variable, or runs a command with a modified environment.

Pipe it through grep to find a particular setting, such as a proxy or locale. It is also why many scripts begin with #!/usr/bin/env bash or #!/usr/bin/env python3: env finds the interpreter by searching PATH instead of assuming a fixed location.

Shell
env

Print all environment variables.

Shell
env | grep -i proxy

Check for proxy settings.

Shell
env NODE_ENV=production node server.js

Run a command with an extra variable set.

Shell
printenv HOME

Print the value of a single variable.

-i
Start the command with an empty environment, PATH included.
-u <name>
Remove one variable for the command.

echo $PATH

Shows the list of folders the shell searches, in order, when you type a command name.

PATH is a colon-separated list, and the first folder that contains a matching program wins, which is how two installed versions of a tool end up competing. The current folder is deliberately left out, so you run a script sitting in it as ./script.sh. To add a folder, set PATH in ~/.bashrc and include the existing $PATH in the new value so you do not lose everything else.

Shell
echo "$PATH" | tr ':' '\n'

Print each folder on its own line.

Shell
export PATH="$HOME/.local/bin:$PATH"

Put your own bin folder first for this session.

Shell
./deploy.sh

Run a script from the current folder, which PATH does not include.

Shell
type -a python3

Every place a command is found, in search order.

which <command>

Prints the full path of the program that runs when you type a command name.

It answers questions like which of two installed Python versions you are actually getting. which only searches PATH, so it cannot see aliases, shell functions, or builtins such as cd; the bash builtin type reports all of those, and command -v is the portable choice in scripts.

Shell
which python3

Show where python3 is found.

Shell
which -a node

List every matching program on PATH, not just the first.

Shell
type ll

Explain whether a name is an alias, function, builtin, or file.

Shell
command -v git

Print the path, or nothing if git is missing, which suits scripts.

-a
Print all matches instead of stopping at the first.

alias name='command'

Creates a short name that expands into a longer command.

An alias lasts only for the current shell session, so add the line to ~/.bashrc to keep it. Running alias by itself lists what is already defined, and many distributions preset a few, such as ll. Putting a backslash in front of a name, as in \ls, skips the alias once and runs the real command.

Shell
alias ll='ls -lah'

Type ll to get a detailed listing.

Shell
alias gs='git status'

Shorten a command you run all the time.

Shell
alias

List every alias in this shell.

Shell
unalias ll

Remove an alias.

history

Lists the commands you have run recently, each with a number.

Press Ctrl+R and start typing to search back through history, often faster than scrolling. !! repeats the last command and !42 reruns entry 42. Bash writes history to ~/.bash_history, so passwords or tokens typed on the command line end up there; a command that starts with a space is left out when HISTCONTROL includes ignorespace, as it does in Ubuntu's default settings.

Shell
history

Show the command history.

Shell
history 20

Only the last 20 commands.

Shell
history | grep docker

Find a docker command you ran before.

Shell
!42

Run command number 42 again.

source <file>

Runs the commands in a file inside your current shell, so the variables, aliases, and folder changes it makes stay in effect.

Running a script normally starts a separate child shell, and whatever it sets vanishes when it ends; sourcing avoids that, which is why you run source ~/.bashrc after editing it instead of opening a new terminal. A single dot, as in . ~/.bashrc, does the same and also works in shells that lack the word source. On macOS the default shell is zsh, whose settings live in ~/.zshrc.

Shell
source ~/.bashrc

Load changes you just made to your bash settings.

Shell
. ~/.bashrc

The shorter, more portable spelling.

Shell
source venv/bin/activate

Activate a Python virtual environment in this shell.

Shell
set -a; source .env; set +a

Load KEY=value lines from a .env file and export them all.

cmd1 && cmd2

Combines commands on one line, running the next one only on success, only on failure, or always.

Success means the command exited with status 0. Be careful using a && b || c as a shortcut for if-else, because c also runs when b fails, not only when a does.

Shell
mkdir -p build && cd build

Enter build only if it was created successfully.

Shell
npm test && npm run build

Build only when the tests pass.

Shell
grep -q "debug" config.ini || echo "debug not set"

Print a message only when the search finds nothing.

Shell
cd project; ls

Run both commands, even if the first one fails.

&&
Run the next command only if the previous one succeeded.
||
Run the next command only if the previous one failed.
;
Run the next command regardless of the result.

Packages and services

Install software with your distribution's package manager, then manage long-running services with systemd. Debian and Ubuntu use apt, Fedora and RHEL use dnf, and most mainstream distributions run services under systemd.

sudo apt install <package>

Installs, upgrades, and removes software on Debian, Ubuntu, and related distributions.

Run sudo apt update first: it refreshes the list of available versions but installs nothing, while apt upgrade actually installs newer versions of what you have. apt search and apt show find and describe packages without sudo. apt is designed for people at a terminal, so scripts usually call apt-get, whose output and options stay stable between releases.

Shell
sudo apt update

Refresh the package lists from the repositories.

Shell
sudo apt install curl git

Install one or more packages.

Shell
sudo apt upgrade

Upgrade installed packages to the newest available versions.

Shell
sudo apt remove nginx

Uninstall a package, leaving its configuration files in place.

-y
Answer yes to confirmation prompts automatically.
--no-install-recommends
Skip optional recommended packages to keep the install small.

sudo dnf install <package>

Installs, upgrades, and removes software on Fedora, RHEL, and related distributions.

dnf refreshes its repository information automatically once it is out of date, so there is no separate update step before installing. dnf upgrade brings every package up to date, with dnf update accepted as another name for it, and older RHEL and CentOS releases use yum, which takes much the same commands.

Shell
sudo dnf install git

Install a package.

Shell
sudo dnf upgrade

Upgrade every installed package.

Shell
dnf search nodejs

Look for packages by name or description.

Shell
sudo dnf remove nginx

Uninstall a package.

-y
Answer yes to all prompts.

systemctl status <service>

Controls systemd services: starts, stops, and restarts them, and decides which launch at boot.

status shows whether a service is running, its main PID, and its latest log lines, so it is the first check when something is down. start and stop act right now, while enable and disable only decide what happens at the next boot, and enable --now does both. After editing a unit file run sudo systemctl daemon-reload so systemd picks up the change; many containers and some WSL setups do not run systemd, so these commands will not work there.

Shell
systemctl status nginx

See whether nginx is running, plus its latest log lines.

Shell
sudo systemctl restart nginx

Stop and start the service, for example after changing its configuration.

Shell
sudo systemctl enable --now nginx

Start it now and every time the machine boots.

Shell
systemctl list-units --type=service --state=running

List the services that are currently running.

--now
With enable or disable, also start or stop the service immediately.
--failed
Show units that failed to start.
--type=service
With list-units, limit the list to services.

journalctl -u <service>

Reads the logs collected by systemd, for the whole system or for one service.

Entries appear oldest first inside a pager, so add -e to jump to the end, -f to follow new lines, or -n for only the latest ones. Reading system services' logs usually needs sudo or membership in the adm or systemd-journal group.

Shell
journalctl -u nginx

Everything the nginx service has logged.

Shell
journalctl -u nginx -f

Follow new log lines as they arrive, like tail -f.

Shell
journalctl -u nginx --since "1 hour ago"

Only entries from the last hour.

Shell
journalctl -b -p err

Errors and anything more severe logged since the last boot.

-u <unit>
Show logs for one service.
-f
Keep printing new entries as they are written.
-n <lines>
Show only the most recent lines.
--since <time>
Start from a point in time, such as "yesterday" or "1 hour ago".