Files
docudjeex/content/en/2.general/5.linux/1.cli-basics.md
T

12 KiB

title, description
title description
Command line basics Understand how a Linux command is built, learn the essential terminal commands, what their names mean, and get a cheat sheet to keep at hand.

:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}

A server has no desktop, no icons and no mouse. Everything happens in a terminal, and that black window with a blinking cursor is the single thing that puts people off self-hosting. It shouldn't: the terminal is just a conversation. You type one line, the machine does exactly that and answers. Nothing more magic than a search bar, except it does far more and never hides an option behind three menus.

The good news is that you don't need to know a hundred commands. Ten of them cover almost everything you'll do on a home server, and they all follow the same pattern. Learn the pattern first, and every command you meet later becomes readable, even the ones you've never seen.

How a command is built

Every command line, without exception, is the same sentence: what to run, how to run it, what to run it on.

sudo apt install -y nano
│    │   │       │  └─ argument: what the command works on
│    │   │       └──── option: changes how it behaves
│    │   └──────────── subcommand: what the program should do
│    └──────────────── the program you're running
└───────────────────── run it with administrator rights

Read out loud, that line says "as an administrator, ask the package manager to install the nano package, and don't ask me to confirm". Spaces are what separate the pieces, which is why a folder named My Backups has to be quoted (cd "My Backups") or the shell reads it as two different things.

Options, short and long

Options change how a command behaves. They come in two flavours, and most commands accept both:

  • Short, a single dash and a single letter: ls -a. They can be stacked, so ls -l -a -h is usually written ls -lah.
  • Long, two dashes and a whole word: ls --all. Longer to type, but you can still tell what it does six months later, which is why they're the better choice in a script.

Some options expect a value right after them: ssh-keygen -t ed25519 (-t for type), rsync --exclude @eaDir. And case matters, always. In ls, -r reverses the sort order while -R walks into subfolders. Two different things, one letter apart.

Arguments and paths

The argument is the target: a file, a folder, a package name, an address. Many commands accept several at once, separated by spaces, which is what makes the terminal fast: rm file1.txt file2.txt file3.txt deletes three files in one go.

When the target is a place on the disk, you write it as a path, and there are a few shortcuts worth knowing:

Path Means
/ the root of the whole system, everything lives under it
~ your own home folder, /home/username
. the folder you're currently in
.. the folder just above
/var/log an absolute path, same result from anywhere
logs/today a relative path, understood from where you currently stand

Which folder holds what is a subject of its own, covered in folders and partitions.

The prompt itself tells you where you are: in username@serveex:~/docker$, you're logged in as username on the machine named serveex, inside the docker folder of your home. That final $ means a normal user. If it ever shows #, you're root and every typo counts double.

Getting help

Two habits make you independent from tutorials. command --help prints a quick summary of every option, and man command opens the full manual (man for manual), which you leave by pressing :kbd{value="Q"}.

::tip{icon=""} Tip: three keyboard habits that change everything: :kbd{value="Tab"} completes the file or folder name you started typing, so you almost never type a full path; the :kbd{value="Up"} arrow brings back your previous commands, which saves retyping a long line for one character; and :kbd{value="Ctrl"} + :kbd{value="C"} stops whatever is currently running. ::

Chaining commands

Once the pattern clicks, commands can be plugged into each other:

  • && runs the next one only if the previous one succeeded: sudo apt update && sudo apt full-upgrade
  • |, the pipe, feeds the output of one command into another: ls -l | grep backup lists the folder, then keeps only the lines containing "backup"
  • > writes the output into a file instead of the screen, and >> adds to the end of that file: df -h > disk-report.txt

The commands you'll actually use

Most command names are abbreviations of an English phrase. Once you know what they stand for, they stop looking like keyboard noise.

pwd, print working directory

Tells you where you are. It changes nothing, it just answers the question.

pwd
/home/username/docker

ls, list

Lists what's in the current folder. On its own it prints bare names, so it's almost always used with options: -l for the long format with sizes, dates and permissions, -a to also show hidden files (the ones starting with a dot), -h for sizes in K/M/G instead of raw bytes.

ls -lah
total 20K
drwxr-xr-x  4 username username 4.0K Sep  5 10:12 .
drwxr-xr-x 18 username username 4.0K Sep  4 21:03 ..
-rw-r--r--  1 username username  512 Sep  5 10:12 .env
-rw-r--r--  1 username username 1.2K Sep  5 09:58 compose.yaml
drwxr-xr-x  3 username username 4.0K Sep  2 18:44 immich

The first column is the permissions, d at the very start meaning it's a folder. Then the owner, the size, the date of the last change, and the name.

cd, change directory

Moves you around. With a path it goes there, with .. it goes up one level, and with nothing at all it takes you back home.

username@serveex:~/docker$ cd /var/log
username@serveex:/var/log$ cd ..
username@serveex:/$ cd
username@serveex:~$

Notice the prompt following you around: it always shows where you currently stand, so you rarely need pwd in practice.

mkdir, make directory

Creates a folder. Several at once if you list them, and -p creates the whole chain of parents in one shot, which is the version you'll actually use.

mkdir backups
mkdir -p docker/immich/config

Nothing. That's not a bug, it's the rule: most commands say nothing when they succeed and only speak up when something goes wrong. Silence is good news, and ls confirms the folder is there.

cp and mv, copy and move

cp copies, mv moves. Same shape both times: first the source, then the destination. Copying a folder needs -r, for recursive, since a folder means everything inside it too. mv doubles as the rename command, because renaming a file is just moving it to a new name.

cp compose.yaml compose.yaml.bak
cp -r config/ config-backup/
mv old-name.txt new-name.txt
ls
compose.yaml  compose.yaml.bak  config  config-backup  new-name.txt

Three silent commands, and ls showing the result: the copy sits next to the original, the folder was duplicated, and old-name.txt is gone because moving it to another name is exactly what renaming means.

rm, remove

Deletes. There is no recycle bin, no undo, no confirmation dialog. -r deletes a folder and its contents, -f forces without asking.

::warning rm -rf is the command that wipes homelabs. It doesn't check, doesn't warn, and doesn't stop. Read the path twice before pressing :kbd{value="Enter"}, especially when the line starts with sudo and contains a / or a *. ::

cat and nano, read and edit

cat (short for concatenate) dumps a whole file to the screen, perfect for a short config. For anything longer, less scrolls through it (named as a joke on more, the older pager it replaced), and you quit it with :kbd{value="Q"}.

To actually change a file, nano opens a simple editor: arrows to move, :kbd{value="Ctrl"} + :kbd{value="O"} to save, :kbd{value="Ctrl"} + :kbd{value="X"} to leave.

cat .env
PUID=1000
PGID=1000
TZ=Europe/Paris

grep, search inside files

grep stands for global regular expression print, which is a mouthful for "find me this text". You give it what to look for and where, and it prints every matching line. -r searches a whole folder, -i ignores upper and lower case, -n shows line numbers.

grep -rin "password" /home/username/docker
/home/username/docker/immich/.env:6:DB_PASSWORD=changeme
/home/username/docker/vaultwarden/compose.yaml:14:  ADMIN_PASSWORD=hunter2

Each line is the file, then the line number inside it, then the matching line itself. Very handy for the day you can't remember which stack holds a setting.

sudo, run as administrator

Substitute user do. A normal user can't touch the system's files, which is exactly what protects you from wrecking the machine by accident. Prefixing a command with sudo runs that single command with administrator rights, and asks for your password the first time.

nano /etc/ssh/sshd_config
Error writing /etc/ssh/sshd_config: Permission denied
sudo nano /etc/ssh/sshd_config
[sudo] password for username:

::note If a command answers Permission denied, that's usually the whole problem: it needed sudo. Resist the reflex of putting sudo on everything though, a file created as root will keep annoying you afterwards because your normal user no longer owns it. ::

Cheat sheet

The ones worth keeping at hand, and where their names come from.

Command Short for What it does
pwd print working directory Shows where you are
ls list Lists files and folders
cd change directory Moves you somewhere else
mkdir make directory Creates a folder
touch plain English Creates an empty file, or refreshes its date
cp copy Copies a file or folder
mv move Moves or renames
rm remove Deletes, permanently
cat concatenate Prints a file to the screen
less a pun on more Scrolls through a long file
nano the editor replacing Pico Edits a file
grep global regular expression print Searches for text
find plain English Searches for files by name, size or date
man manual Opens a command's full documentation
df disk free Shows free space per partition
lsblk list block devices Draws the tree of disks and partitions
du disk usage Shows what a folder weighs
ps process status Lists running processes
htop Hisham's top Live view of CPU, RAM and processes
kill plain English Stops a process by its number
chmod change mode Changes a file's permissions
chown change owner Changes who owns a file
sudo substitute user do Runs one command as administrator
apt advanced package tool Installs, updates and removes packages
systemctl control systemd Starts, stops and enables services
ssh secure shell Opens a session on a remote machine
scp secure copy Copies files over SSH
tar tape archive Packs and unpacks archives
wget web get Downloads a file from a URL
curl client URL Sends a request to a URL
history plain English Lists the commands you typed before

::tip{icon=""} Tip: nobody memorises this. You'll look up the same three options for weeks, then one day realise you're typing them without thinking. Until then, --help and this table are perfectly legitimate. ::