Post
Linux commands: my cheat sheet
The Linux commands worth knowing by heart, grouped by task: files, searching, text, permissions, processes, services and logs, disk, networking, archives, packages, SSH and shell tricks.
The commands I reach for on a Linux server, in a container or in a CI job. Examples assume GNU/Linux with a Bash-like shell; on a Mac the BSD versions differ in details, and I say so where it matters. Linux is case-sensitive: File.txt and file.txt are different files. Anything marked ⚠️ can destroy data: run the harmless version first (ls before rm, find without -delete) and look. A throwaway Linux to practice on is one command away: docker run --rm -it ubuntu bash (see Docker from zero to hero).
Getting help
man <command>opens the manual page. Use/wordto search inside it,nfor the next match, andqto quit.<command> --helpprints a short usage summary.man -k <word>(orapropos <word>) searches manual pages by keyword when you don’t know the command’s name.type <command>shows whether something is a program, a shell built-in or an alias, andwhich <command>shows the path of the program that would run.- The GNU Coreutils manual covers the core file and text tools in depth.
Where am I, and moving around
pwdprints the current directory, andcd <dir>changes it.cdalone goes home,cd -jumps back to the previous directory, andcd ..goes up one level.lslists files.ls -lis the long format,ls -aincludes hidden files (names starting with a dot),ls -hmakes sizes human-readable, and they combine:ls -lah. Add-tto sort by modification time and-Sby size.~means your home directory,.is the current directory and..is its parent.- Press Tab to complete names and Tab Tab to list the options.
Working with files and folders
touch <file>creates an empty file, or updates the modification time of an existing one.mkdir <dir>creates a directory, andmkdir -p a/b/ccreates the whole path (no error if it already exists).cp <src> <dst>copies a file,cp -r <dir> <dst>copies a directory, andcp -acopies and preserves permissions and times.mv <src> <dst>moves or renames. Likecp, it silently overwrites an existing destination: add-ito be asked first, or-nto never overwrite.rm <file>deletes a file.rm -r <dir>deletes a directory and everything in it, andrm -rf <dir>does it without asking ⚠️. There is no trash can. Read the path twice, and beware of variables (rm -rf "$DIR/"with an empty$DIRis the classic disaster).ln -s <target> <link>creates a symbolic link (a pointer to a path). Without-sit makes a hard link.file <name>tells what kind of file it is, andstat <file>shows size, permissions, owner and timestamps.- Quote names with spaces:
cp "My File.txt" backup/.
Looking at files
cat <file>prints a file, andcat a b > cjoins files.less <file>is the viewer for long files: arrows orSpaceto scroll,/wordto search,qto quit.less +F <file>follows a file liketail -f(Ctrl-Cto stop following).head <file>shows the first 10 lines andtail <file>the last 10.-n 50changes the count.tail -f <file>keeps the file open and prints new lines as they arrive, which is how you watch a log.tail -Falso survives log rotation.wc -l <file>counts lines (-wwords,-cbytes).diff a bshows the differences between two files, anddiff -u a bprints them in the familiar unified format.
Searching
grep "text" <file>prints the matching lines. The flags you’ll use:-iignore case,-nshow line numbers,-vinvert (lines that don’t match),-ccount matches,-wwhole words,-Eextended regular expressions, and-A 2/-B 2/-C 2for lines after, before and around each match.grep -rn "text" .searches every file under the current folder. Add--include='*.py'to limit it by name, and-lto list only the files that match.find <where> <tests>finds files by their properties:
find . -name "*.log" # by name (quote the pattern, or the shell expands it)
find . -iname "readme*" # same, ignoring case
find . -type d -name node_modules # only directories (f = files)
find . -type f -size +100M # bigger than 100 MiB
find . -mtime -1 # modified in the last 24 hours
find . -mtime +30 # modified more than 30 days ago
find . -mmin -10 # modified in the last 10 minutes
find . -name "*.tmp" -delete # delete matches ⚠️ (put -delete last, and run without it first)
find . -name "*.sh" -exec chmod +x {} + # run a command on the matches
find / -name "nginx.conf" 2>/dev/null # search everywhere, hide "permission denied" noise
find ... -print0 | xargs -0 <command>is the safe way to feed filenames to another command, because it copes with spaces and newlines in names.locate <name>searches a prebuilt index and is much faster thanfind, but needsplocateormlocateand an updated index (sudo updatedb).
Pipes, redirection and chaining
a | bsends the output ofaintob.cmd > filewrites the output to a file, replacing it ⚠️.cmd >> fileappends.cmd < filereads input from a file.- Every program has two output streams: standard output (1) and standard error (2).
cmd 2> errors.txtredirects only the errors,cmd > out.txt 2>&1sends both to the same file, andcmd > /dev/null 2>&1throws everything away (/dev/nullis the bin). cmd | tee fileshows the output and also saves it.tee -aappends.$(cmd)substitutes a command’s output into another command:echo "Today is $(date +%F)".a && brunsbonly ifasucceeded,a || brunsbonly ifafailed, anda; bruns both regardless.$?holds the exit code of the last command:0means success.
Processing text
cut -d: -f1,3 /etc/passwd # fields 1 and 3, split on ":"
awk -F: '{print $1}' /etc/passwd # the first field, with awk
sort file.txt | uniq -c | sort -rn | head # the most frequent lines, ranked
tr 'a-z' 'A-Z' < file.txt # translate characters (here: upper-case)
sed 's/old/new/g' file.txt # replace in the output (file unchanged)
sed -n '10,20p' file.txt # print only lines 10 to 20
sortsorts lines.-nsorts numerically,-rreverses,-uremoves duplicates, and-k2sorts by the second column.uniqcollapses adjacent identical lines, so sort first.uniq -cprefixes each line with how many times it occurred.sed -i 's/old/new/g' fileedits the file in place ⚠️. On macOS it needs a suffix argument:sed -i '' .... Run it without-ifirst.awkis a tiny language for columns:awk '{sum += $3} END {print sum}' fileadds up the third column.xargsturns input lines into arguments:cat urls.txt | xargs -n 1 curl -sI.jq(usually installed separately) isgrepandsedfor JSON:curl -s <url> | jq '.items[0].name'.
Permissions and ownership
ls -l shows who can do what. The string -rwxr-xr-- is a file type, followed by three triplets for the owner, the group and everyone else. Each triplet is read (r, 4), write (w, 2) and execute (x, 1), and adding the numbers gives the octal form chmod uses.
chmod 755 <file>sets the permissions numerically. Common values:644for files (owner writes, everyone reads),755for scripts and directories,600for secrets such as SSH keys.chmod +x <file>makes a file executable,chmod u+w <file>adds write for the owner, andchmod go-rwx <file>removes everything for group and others.chmod -R u+rwX,go-w <dir>changes a whole tree. The capitalXadds execute only to directories and files that already have it.- On a directory,
xmeans “may enter it and reach the files inside”. chown <user>:<group> <file>changes the owner and group (it needssudounless you already own the file).-Rapplies it recursively ⚠️, so check the path first.sudo <command>runs one command as root.sudo -iopens a root shell, andsudo -u <user> <command>runs as someone else. Prefer a singlesudocommand to staying in a root shell.whoamiprints your user name,idyour user and group IDs,groupsyour groups.chmod -R 777is almost never the answer ⚠️: it lets anyone write to everything. Grant exactly the access a user needs.
Processes
ps auxlists every process with its owner, CPU and memory use, andps -efadds parent process IDs.ps aux --sort=-%mem | headshows the biggest memory users on GNU/Linux.pgrep -af <name>finds processes by name and prints their command lines.topis the live view of what’s busy: pressqto quit,Mto sort by memory andPby CPU.htopis a nicer version you usually install yourself.kill <pid>asks a process to stop politely (SIGTERM).kill -9 <pid>forces it with SIGKILL, with no chance to clean up, so use it only when the polite way failed ⚠️.pkill <name>andkillall <name>do the same by name, so check that the pattern doesn’t match more than you meant.jobs,fgandbgmanage jobs in your shell:Ctrl-Zsuspends the running command,bgcontinues it in the background,fgbrings it back. End a command with&to start it in the background.nohup <command> &keeps a command running after you log out. For anything long-lived, a service (below) ortmux/screenis better.lsof -i :8080shows what is using a port, andlsof <file>shows who has a file open.
Services and logs (systemd)
Most modern Linux distributions manage services with systemd (docs). (Not on a Mac, and usually not inside a container.)
systemctl status <service>shows whether a service is running and its latest log lines.sudo systemctl start|stop|restart|reload <service>controls it now;reloadre-reads the configuration without a full restart, if supported.sudo systemctl enable <service>starts it at boot,disableturns that off, andenable --nowalso starts it immediately.systemctl list-units --type=servicelists the services, andsystemctl --failedlists the ones that failed.sudo systemctl daemon-reloadmakes systemd re-read unit files after you edit them.
journalctl reads the logs systemd collects:
journalctl -u nginx # logs of one service
journalctl -u nginx -f # follow them live
journalctl -u nginx -n 100 # the last 100 lines
journalctl -b # everything since this boot (-b -1 = the previous boot)
journalctl --since "1 hour ago" # a time window (also --until)
journalctl -p err # only errors and worse
journalctl -k # kernel messages, like dmesg
journalctl --disk-usage # how much space the journal takes
Plain log files still live in /var/log for many programs: tail -f /var/log/syslog (Debian and Ubuntu) or /var/log/messages (Red Hat family).
Disk and memory
df -hshows free space per filesystem. A full disk is the cause of a surprising number of “it just stopped working” incidents.du -sh <dir>shows a directory’s total size, anddu -h -d 1 . | sort -hshows each folder one level down, smallest first, so the culprit is at the bottom. (sort -his a GNU option.)ncduis an interactive disk-usage browser, installed separately: the quickest way to find what filled the disk.free -hshows memory and swap. Read the “available” column, not “free”: Linux uses spare memory as cache.uptimeshows how long the machine has been up and the load averages, andlsblklists disks and partitions.mount | grep <path>andfindmntshow what’s mounted where.ddwrites raw bytes to a device ⚠️: point it at the wrong one and it overwrites a whole disk.
Networking
ip addr(short:ip a) shows the machine’s addresses, andip routeshows the routing table. These replaced the olderifconfigandroute.ss -tulpnlists listening sockets:-tTCP,-uUDP,-llistening only,-pthe owning process,-nnumbers instead of names (usesudoto see other users’ processes).ss -sprints a summary, andss -tn 'sport = :80'narrows it to one port. (netstatis the old tool.)ping -c 4 <host>checks that a host answers (-climits the count, otherwise it runs forever).curl <url>fetches a URL. The flags worth knowing:-Iheaders only,-ssilent,-Lfollow redirects,-o <file>save to a file,-ffail on HTTP errors,-X POST -d '{"a":1}' -H 'Content-Type: application/json'to send data.curl -fsSL <url> -o fileis the reliable download.wget <url>also downloads.dig <domain> +short(ornslookup) looks up DNS records, anddig <domain> MXasks for a specific type.nc -zv <host> <port>tests whether a TCP port is reachable.traceroute <host>shows the hops along the way (it may need installing).curl -fsSL <url> | shruns a script straight from the internet ⚠️. Download it, read it, and then run it.
SSH and copying files
ssh user@host # log in
ssh -i ~/.ssh/key.pem user@host # with a specific key
ssh -p 2222 user@host # a different port
ssh user@host 'df -h' # run one command and come back
ssh-keygen -t ed25519 -C "me@laptop" # create a key pair
ssh-copy-id user@host # install your public key on the server
scp file.txt user@host:/tmp/ # copy a file to the server
scp user@host:/var/log/app.log . # copy a file from the server
rsync -avzP ./site/ user@host:/var/www/site/ # sync a folder, resumable, with progress
rsync -avzn --delete ./site/ user@host:/var/www/site/ # dry run (-n) of a mirror
- Private keys must be private:
chmod 600 ~/.ssh/key.pem, or SSH refuses to use them. ~/.ssh/configlets you give a server a short name, sossh myserverreplaces the long line.rsyncis the better copy tool: it transfers only what changed. The trailing slash matters:site/copies the folder’s contents,sitecopies the folder itself.--deleteremoves destination files missing from the source ⚠️, so dry-run (-n) first.
Archives and compression
tar czf backup.tar.gz <dir>creates a gzip-compressed archive:ccreate,zgzip,fthe file name that follows. UseJinstead ofzfor xz, andjfor bzip2.tar xzf backup.tar.gzextracts it,tar tzf backup.tar.gzlists the contents, and-C <dir>extracts elsewhere:tar xzf backup.tar.gz -C /tmp/restore. Add-vto see each file. Moderntar xfusually detects the compression itself.tar czf backup.tar.gz --exclude=node_modules <dir>leaves things out.gzip <file>compresses a single file (and replaces it with<file>.gz), andgunzip <file>.gzreverses it.zip -r archive.zip <dir>andunzip archive.ziphandle the Windows-friendly format, and may need installing.
Installing software
The command depends on the distribution:
sudo apt update && sudo apt install -y curl # Debian, Ubuntu
sudo dnf install curl # Fedora, RHEL and relatives
sudo apk add curl # Alpine (common in containers)
sudo pacman -S curl # Arch
- On Debian and Ubuntu,
apt updaterefreshes the package list andapt upgradeinstalls available updates.apt search <word>finds packages,apt remove <pkg>uninstalls, anddpkg -l | grep <word>shows what’s installed. cat /etc/os-releasetells you which distribution and version you’re on, so you pick the right line above.
About the system and your session
uname -ashows the kernel and architecture,hostnamectlshows the host name and OS, anddateshows the time.date +%Fprints it as2026-10-10, which is handy in file names.env(orprintenv) lists environment variables,echo "$PATH"shows where the shell looks for programs, andexport NAME=valuesets a variable for the programs you start from this shell.historylists past commands.Ctrl-Rsearches them as you type, which is faster than the arrow keys.alias ll='ls -lah'creates a shortcut for this session. To keep it, add the line to~/.bashrc.crontab -eedits your scheduled jobs andcrontab -llists them. A line has five time fields and then the command:30 2 * * * /home/me/backup.shruns at 02:30 every day (minute, hour, day of month, month, day of week).sudo shutdown -h nowandsudo rebootdo what they say ⚠️. On a remote machine, make sure you really mean it.
Shell shortcuts worth learning
Ctrl-Cstops the running command,Ctrl-Dends input (and logs out of an empty prompt),Ctrl-Lclears the screen,Ctrl-Zsuspends the command.Ctrl-AandCtrl-Ejump to the start and the end of the line,Ctrl-Wdeletes the previous word andCtrl-Udeletes up to the start.!!repeats the previous command, sosudo !!is “I forgot sudo”.!$is the last argument of the previous command.