Cheat Sheets

Linux Commands Cheat Sheet for Ubuntu and Rocky Linux (PDF)

A Linux commands cheat sheet written for one distro will mislead you on another in 2026. Ubuntu 26.04 now runs Rust rewrites of ls, cat and date while keeping GNU cp, mv and rm, and Rocky Linux 10’s older GNU coreutils rejects a cp flag that Ubuntu accepts.

Original content from computingforgeeks.com - post 161451

This Linux commands cheat sheet covers the commands admins use every day, grouped by job: files and directories, search, viewing and editing, permissions, archives, disks, processes, users and networking. File management gets the deepest treatment, and every block with output was run in October 2026 on Ubuntu 26.04 and Rocky Linux 10.2, with the distro differences shown side by side. The errors these commands print, and the fixes, have their own section near the end.

Find the Linux command for the job

Start here when you know what you need to do but not which command does it. Each row is covered with examples further down:

JobCommand
Where am I, what’s herepwd, ls -lah
Copy a directory with permissions intactcp -a src/ dest/
Copy without overwritingcp --update=none src dest
Swap two files or directories atomicallymv --exchange -T a b
Delete with a confirmation for big jobsrm -rI dir/
Find files by namefind /etc -name '*.conf'
Find text inside filesgrep -rn 'pattern' /etc
Follow a logtail -f /var/log/syslog (Ubuntu) or sudo tail -f /var/log/messages (Rocky, root only)
Change permissions and ownerchmod 640 file, chown user:group file
Make a file undeletable, even by rootsudo chattr +i file
Archive and compress a directorytar czf backup.tgz dir/
Disk space, then inodesdf -h, df -i
What is using the spacedu -sh * | sort -h
What is runningps aux --sort=-%cpu | head
Stop a non-service process by namepkill -f 'python app.py'
Service status and logssystemctl status nginx, journalctl -u nginx
IP addresses and listening portsip -br a, ss -tulpn

Check which coreutils your system runs

Ubuntu 26.04 replaced most of GNU coreutils with uutils, a Rust rewrite, but kept the GNU versions of the commands that move and delete data. Check before you trust a flag or an error message, because the two implementations print different things. A version check on each command shows which one answers:

for c in ls cp mv rm df true date cat; do printf '%-5s ' $c; $c --version 2>&1 | head -1; done

On Ubuntu 26.04 the split is visible straight away. true prints nothing because the shell’s built-in true answered instead of the binary:

ls    ls (uutils coreutils) 0.10.0
cp    cp (GNU coreutils) 9.7
mv    mv (GNU coreutils) 9.7
rm    rm (GNU coreutils) 9.7
df    df (GNU coreutils) 9.7
true  date  date (uutils coreutils) 0.10.0
cat   cat (uutils coreutils) 0.10.0

Rocky Linux 10.2 printed (GNU coreutils) 9.5 for every one of them. On Ubuntu, the GNU tools stay installed under a gnu prefix, 104 of them on our box from gnucp to gnudate. Call gnuls or gnudate to get the GNU behaviour for one command when a script depends on it. readlink -f /usr/bin/ls shows which binary a name points to: /usr/lib/cargo/bin/coreutils/ls for uutils, /usr/bin/gnucp for GNU. One side effect caught us out: the uutils tools are one multi-call binary that picks its behaviour from its own name, so a copy of sleep saved as /tmp/s refused to run with coreutils: unknown program 's'. Our Ubuntu 26.04 Rust coreutils guide explains the switch. It was written for the 0.8.0 release, and updates have since moved uutils to 0.10.0; df was GNU on 26.04 from the start.

Navigation is where most people start, and ls has the most flags worth memorising. These work the same on both distros unless a row says otherwise:

CommandWhat it does
pwdPrint the current directory
cd /var/log, cd -, cd (home)Change directory, go back, go home
ls -lahLong list, hidden files, human sizes
ls -ltrSort by time, newest last (good for logs)
ls -lSSort by size, largest first
ls -ld dirShow the directory itself, not its contents
ls -ZSELinux context (Rocky); prints ? on Ubuntu’s AppArmor
tree -L 2Directory tree two levels deep (install tree)
stat fileSize, inode, permissions and all timestamps
file fileWhat kind of file it really is
mkdir -p a/b/cCreate nested directories in one go
touch fileCreate an empty file or update its timestamp

Two newer ls options split the distros. ls --sort=name worked on Ubuntu, where ls is the uutils version. Rocky’s GNU 9.5 rejected it as invalid argument ‘name’ for ‘--sort’, because GNU only added that value in 9.6. ls --hyperlink=always worked on both and wraps each name in a clickable link for terminals that support them. For more listing patterns, see the ls command examples.

Copy, move and delete files safely

These are the commands that lose data when you get a flag wrong, so they deserve the most care. cp -r copies a tree but resets ownership and timestamps to yours. cp -a preserves everything, which is what you want for backups and config directories:

CommandWhat it does
cp file /tmp/Copy a file
cp -a src destCopy a tree with permissions, timestamps and links (owners too when run as root). If dest already exists, the copy lands in dest/src; rsync -a src/ dest/ copies the contents instead
cp -i src destAsk before overwriting
cp --update=none src destNever overwrite an existing file, silently (coreutils 9.3+)
cp --update=none-fail src destNever overwrite, and fail with an error (GNU 9.6+, not Rocky 10)
mv old newRename or move
mv -n src destMove without overwriting
mv --exchange -T a bSwap two paths atomically (coreutils 9.5+, same filesystem)
rm -i fileAsk before each delete
rm -rI dir/Ask once before deleting more than three files or recursively
rsync -aHAX --dry-run src/ dest/Preview a copy that keeps hard links, ACLs and xattrs

The no-overwrite flags are where the two distros part ways. We copied one empty file onto another with -n, then with --update=none-fail:

cd $(mktemp -d) && touch a b && cp -n a b; echo "cp -n exit=$?"; cp --update=none-fail a b; echo "none-fail exit=$?"

Ubuntu warns that -n is non-portable but still skips the file, and the newer flag fails as designed. The warning is Ubuntu’s own: its cp carries a patch that keeps the old skip behaviour of -n, which upstream GNU changed for a while. Debian dropped that patch, so a Debian 13 box behaves like upstream:

cp: warning: behavior of -n is non-portable and may change in future; use --update=none instead
cp -n exit=0
cp: not replacing 'b'
none-fail exit=1

Rocky’s 9.5 skipped silently on -n and then refused the newer flag outright, listing only all, none and older as valid values. A script that relies on --update=none-fail to stop on a conflict therefore fails for the wrong reason on Rocky 10. Use --update=none and check the target yourself when one script runs on both. On older systems even that flag is missing, because it arrived in coreutils 9.3, so RHEL 9 and Ubuntu 22.04 reject it too; there, [ -e dest ] || cp src dest is the portable form. Upstream GNU 9.2 made cp -n exit 1 on a skipped file, and 9.3 added the not replacing message, until 9.5 went back to a silent skip. Ubuntu patches that back, so Ubuntu 24.04 behaves like 26.04: the same warning, the file skipped, exit 0.

mv --exchange is the newest trick here. It swaps two paths in one atomic rename, so a deploy can switch a live directory with a new one without a window where neither exists. It needs GNU coreutils 9.5 or newer and both paths on the same filesystem, and it worked on both distros:

cd $(mktemp -d) && mkdir x y && echo one > x/f && echo two > y/f && mv --exchange -T x y && cat x/f y/f; echo "exit=$?"

The contents swapped, so x/f now holds what was in y/f:

two
one
exit=0

For whole-tree copies across machines, rsync beats cp because it resumes and only sends changes; the rsync examples guide covers the flags, and the cat and cp guide has more copy patterns.

Find files and search inside them

find searches the file tree live, and grep searches inside files. Both are installed everywhere, and the faster fd and rg alternatives are covered at the end of this page:

CommandWhat it does
find /etc -name '*.conf'Find by name (quote the pattern)
find . -type f -mtime -1Files changed in the last day
find . -size +100MFiles over 100 MB
find . -name '*.log' -deleteDelete matches; run with -print first, and keep -delete last
find . -type f -exec chmod 644 {} +Run a command on every match
sudo grep -rn 'error' /var/logSearch a tree, with line numbers
grep -i -E 'fail|error' fileCase-insensitive, extended regex
grep -v '^#' fileHide comment lines
locate nginx.confInstant search of an index (install plocate, run sudo updatedb)
which nginx, type lsWhere a command comes from

Two mistakes account for most find errors, and both are easy to avoid once you have seen them:

  • an unquoted -name pattern, which the shell expands before find sees it
  • an -exec without its \; or + terminator

We ran both on purpose. In a directory with several matching files, the unquoted pattern gives an error instead of results. With exactly one match it is worse: no error, and find silently searches for that one file name only:

cd /etc && find . -maxdepth 1 -name *.conf 2>&1 | head -2; find /etc -maxdepth 1 -name '*.conf' -exec ls {} 2>&1 | head -2

Ubuntu named one of the matching files in the error, and the second command shows the other classic mistake, an -exec with no \; or + at the end:

find: paths must precede expression: `ca-certificates.conf'
find: possible unquoted pattern after predicate `-name'?
find: missing argument to `-exec'

Write grep -E and grep -F in new scripts instead of egrep and fgrep. Rocky’s grep 3.11 printed egrep: warning: egrep is obsolescent; using grep -E, while Ubuntu’s 3.12 package ran egrep without a warning, so whether you are warned depends on the distro. The find command guide has the rest of the tests and actions.

View and edit file contents

Most of these read a file or a stream without changing it, which makes them safe to run on production logs. sed -i is the exception, so keep a backup suffix on it:

CommandWhat it does
cat file, less filePrint a file; page through it (q quits, / searches)
head -n 20 file, tail -n 50 fileFirst or last lines
tail -f fileFollow new lines as they are written
wc -l fileCount lines
sort file | uniq -c | sort -rnCount repeated lines, most common first
cut -d: -f1 /etc/passwdPick a field from delimited text
awk '{print $1}' access.logPrint a column
sed -i.bak 's/old/new/g' fileReplace in place, keeping file.bak
diff -u old newShow changes in unified format
vim file, nano fileEdit a file (Rocky’s cloud image had neither; sudo dnf install vim-enhanced)

Log locations are the distro difference that trips people most here. Ubuntu 26.04 had /var/log/syslog and no /var/log/messages; Rocky had the reverse. journalctl works the same on both, which is why it’s the better habit, and our journalctl filtering guide covers it.

Set permissions, ownership and attributes

Permissions decide who can read, write and run a file, and on Rocky an SELinux label sits on top of them. Read a mode like 640 as owner read and write, group read, others nothing:

CommandWhat it does
chmod 640 fileOwner rw, group r, others none
chmod u+x script.shAdd execute for the owner
chmod -R g+w dir/Add group write to a tree
chown user:group fileChange owner and group
chown -R www-data: /var/wwwRecursive; group set to the user’s own (the web user is www-data on Ubuntu, nginx or apache on Rocky)
umask 027New files get 640, directories 750
sudo chattr +i file, lsattr fileMake a file immutable; show attributes
ls -Z file, sudo restorecon -v fileShow and fix SELinux labels (Rocky)

The immutable attribute is stronger than permissions, because even root cannot delete the file until the attribute is cleared. That is useful for protecting a config from automation and confusing when you forget you set it:

sudo touch /root/imm && sudo chattr +i /root/imm && sudo rm -f /root/imm; echo "exit=$?"; sudo lsattr /root/imm; sudo chattr -i /root/imm && sudo rm -f /root/imm

Both distros refused the delete, and lsattr shows the i flag that explains why (Ubuntu also shows e, the ext4 extents flag):

rm: cannot remove '/root/imm': Operation not permitted
exit=1
----i---------e------- /root/imm

The cleanup at the end of that command, chattr -i followed by rm, is the fix, and it is also the first thing to try when root gets Operation not permitted on a file anywhere else.

Archive and compress files

tar bundles files and compresses them in one step, and the letters are easier to remember as words: c for create, x for extract, t for list, z for gzip, f for file:

CommandWhat it does
tar czf backup.tgz dir/Create a gzip archive
tar cJf backup.tar.xz dir/Create an xz archive (smaller, slower)
tar tzf backup.tgzList contents without extracting
tar xzf backup.tgz -C /restoreExtract into a directory
gzip file, gunzip file.gzCompress or decompress one file
zip -r site.zip dir/, unzip site.zipZip format for Windows users (sudo apt install zip unzip or sudo dnf install zip unzip if missing)

Archiving an absolute path prints tar: Removing leading `/' from member names and still exits 0. That is a safety feature rather than an error: the archive stores etc/hostname instead of /etc/hostname, so extracting it anywhere other than / cannot overwrite the live file by accident.

Check disk space and inodes

A full disk is the most common outage these commands diagnose, and there are two ways to run out: blocks and inodes. Check both before you start deleting:

CommandWhat it does
df -hFree space per filesystem
df -iFree inodes per filesystem
du -sh * | sort -hSize of each item here, largest last
du -xh / --max-depth=1 2>/dev/null | sort -hBiggest top-level directories on one filesystem
ncdu /varInteractive disk usage browser (install ncdu)
lsblk -fDisks, partitions, filesystems and mount points
findmnt /tmpHow a path is mounted
sudo lsof +L1Deleted files still held open (space not freed yet); install the lsof package if missing

Inode exhaustion is the one that confuses people, because df -h looks healthy. We made a small ext4 filesystem with only 128 inodes and created 200 empty files on it:

truncate -s 64M /tmp/i.img && mkfs.ext4 -F -N 128 -q /tmp/i.img && sudo mkdir -p /mnt/i && sudo mount -o loop /tmp/i.img /mnt/i && sudo touch /mnt/i/f{1..200} 2>&1 | tail -1; df -h /mnt/i | tail -1; df -i /mnt/i | tail -1; sudo umount /mnt/i; rm /tmp/i.img

On Ubuntu the write failed with plenty of space left: 1% used by blocks, 100% by inodes (Rocky’s run showed the same 128 of 128 inodes used, with slightly different block figures). Thousands of tiny session or cache files cause this in real life:

touch: cannot touch '/mnt/i/f200': No space left on device
/dev/loop0       60M  152K   56M   1% /mnt/i
/dev/loop0        128   128     0  100% /mnt/i

/tmp is another difference to know. On Ubuntu 26.04 it is a RAM-backed tmpfs with per-user quotas, so it is small and emptied at every boot, while on Rocky it sat on the root disk. Large temporary files belong in /var/tmp on Ubuntu. The ncdu guide shows how to hunt down space quickly.

Manage processes and services

Processes are what is running right now, and services are processes systemd starts and supervises. Use the service commands for anything systemd manages, because systemd tracks the unit’s state: kill its main process with kill -9 and the unit ends up failed, or restarted if its Restart= setting asks for that (the default is no restart). A plain kill sends SIGTERM, which systemd counts as a clean stop, so the unit just goes inactive:

CommandWhat it does
ps aux --sort=-%cpu | headTop CPU users
ps -ef --forestProcess tree
top, btopLive view (btop needs installing)
pgrep -a nginxFind processes by name
kill 1234, kill -9 1234Ask a process to stop; force it
pkill -f 'python app.py'Kill by full command line
nohup cmd > out.log 2>&1 &Keep running after you log out
systemctl status nginxService state and recent logs
journalctl -u nginx -fFollow a service’s log
free -h, uptimeMemory, load average

For long jobs over SSH, a tmux session beats nohup because you can reattach and see the output. Service management has its own systemctl cheat sheet with both distros covered. If you want one book that explains all of this properly, The Linux Command Line (paid link) by William Shotts (third edition, No Starch Press, February 2026) is the one we’d hand a new admin. It covers the shell, files, permissions and scripting from first principles, and it is current enough to be worth buying over the free older editions.

Work with users, sudo and the network

These are the commands for who you are, what you can do, and what the machine can reach. The networking rows use ip and ss, which replaced ifconfig and netstat years ago; neither old tool was installed on our Rocky cloud image:

CommandWhat it does
whoami, idYour user, groups and IDs
sudo -iRoot shell
sudo useradd -m alice, sudo passwd aliceAdd a user with a home directory
sudo usermod -aG wheel aliceAdd to a group (sudo group on Ubuntu)
ip -br a, ip rAddresses, routes
sudo ss -tulpnListening ports and the process behind each (sudo shows every process)
ping -c 3 host, curl -I https://siteReachability, HTTP headers
dig +short example.comDNS lookup (bind9-dnsutils on Ubuntu, bind-utils on Rocky)
ssh user@host, scp file host:/tmp/Remote shell, copy over SSH

sudo itself changed on Ubuntu 26.04, which now uses sudo-rs, a Rust reimplementation. Most flags behave the same, but sudo -E (keep your whole environment) is not supported. It printed sudo: preserving the entire environment is not supported, '-E' is ignored and ran the command anyway, so a script that depends on exported variables under sudo needs --preserve-env=VAR or sudo env VAR=value cmd instead. The SSH commands cheat sheet covers keys, tunnels and config files.

Fix the errors these commands print

Each of these came from our two lab servers. Most look alarming and have a one-line fix once you know what the kernel or the tool is really telling you.

Error: “Argument list too long”

The shell expands * into every file name before the command starts, and the kernel caps the total size of a command line, 2097152 bytes on both of our servers. We created 200,000 files and tried to delete them with a glob:

getconf ARG_MAX; rm -rf /tmp/argmax; mkdir /tmp/argmax && cd /tmp/argmax && seq 1 200000 | sed 's/^/file-with-a-long-name-/' | xargs touch && rm *; echo "exit=$?"

The limit came back first, then the failure from rm, which never started:

2097152
bash: line 1: /usr/bin/rm: Argument list too long
exit=126

Let find do the deleting instead, because it walks the directory itself and never builds a giant command line. find . -type f -name 'file-*' -delete removed all 200,000 files, taking 0.88 seconds on Ubuntu and 1.52 seconds on Rocky, and cd /tmp && rmdir argmax removes the empty test directory. Add -print in place of -delete for a dry run first whenever the pattern touches real data.

Error: “rm: cannot remove … Operation not permitted” as root

Root hitting “Operation not permitted” almost always means the immutable or append-only attribute is set. Run lsattr file, look for i or a, then sudo chattr -i file and delete it, as the permissions section shows.

Error: “Device or resource busy”

You tried to remove a directory that is a mount point. Both rmdir and rm -rf failed this way on a mounted tmpfs. Check with findmnt /path, unmount it, and only then delete it, because deleting a mount point’s contents would wipe the mounted filesystem, not the empty directory under it.

Error: “No space left on device” with free space in df -h

There are three usual causes, so check them in this order before deleting anything:

  • df -i at 100%: no inodes left, however many gigabytes are free
  • sudo lsof +L1 showing deleted files a process still holds open; the space returns when it restarts
  • on Ubuntu, a full /tmp tmpfs or a user hitting its quota

Our test above hit the first one, which is the cause people rule out last because df -h looks fine.

Error: “cp: -r not specified; omitting directory”

cp copies files, not directories, unless you ask. Use cp -a to copy the tree with its permissions, or cp -r if you want the copies owned by you.

Error: “mv: cannot overwrite … Directory not empty”

mv will not replace a non-empty directory with another directory of the same name. Ubuntu’s GNU 9.7 printed Directory not empty, and Rocky’s 9.5 printed mv: cannot overwrite 'b/d': File exists for the same move, so search for both. Merge the contents with rsync -a a/d/ b/d/ and remove the source, or rename one side first.

Error: “cp: invalid argument ‘none-fail’ for --update“

You are on GNU coreutils older than 9.6, such as Rocky Linux 10’s 9.5. Use --update=none (coreutils 9.3 and newer), or [ -e dest ] || cp src dest on older releases such as RHEL 9, and test for the target file yourself if the script must stop on a conflict.

Error: “find: paths must precede expression”

An unquoted pattern was expanded by the shell. Quote it: find . -name '*.conf'. The related find: missing argument to `-exec' means the -exec has no \; or + terminator.

Install the modern replacements

Faster, friendlier versions exist for several classics, and they are worth installing on any machine you work on daily. They are not in either distro’s default install, and two of them use different binary names on Ubuntu, which is what sends people to the forums:

ClassicModernUbuntu 26.04 (apt)Rocky Linux 10 (EPEL)
findfdfd-find, run as fdfindfd-find, run as fd
grep -rripgrepripgrep, rg 15.1.0ripgrep, rg 14.1.1
catbatbat, run as batcatbat, run as bat
lsezaezanot in EPEL 10
duncdu, dufncdu, dufncdu, duf
topbtopbtopbtop
locateplocateplocateplocate (BaseOS, no EPEL needed)

Install them in one line per distro. Rocky needs the EPEL repository first:

sudo apt update && sudo apt install -y ripgrep fd-find bat eza ncdu duf btop fzf plocate tree        # Ubuntu
sudo dnf install -y epel-release && sudo dnf install -y ripgrep fd-find bat ncdu duf btop fzf plocate tree   # Rocky

On Ubuntu, add alias fd=fdfind and alias bat=batcat to ~/.bashrc so commands from other guides work as written. On Rocky, dnf info eza answered Error: No matching Packages to list, so install eza from its upstream release if you want it there. Keep the classics in scripts, though: find, grep and ls are on every server you will ever log in to, and the modern tools are not.

Keep reading

Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) AI Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) OpenAI Codex CLI Cheat Sheet: Shortcuts, Commands, Flags (PDF) AI OpenAI Codex CLI Cheat Sheet: Shortcuts, Commands, Flags (PDF) macOS Keyboard Shortcuts Cheat Sheet (Golden Gate and Tahoe) Cheat Sheets macOS Keyboard Shortcuts Cheat Sheet (Golden Gate and Tahoe) APT Cheat Sheet: apt and apt-get Commands for Ubuntu/Debian Cheat Sheets APT Cheat Sheet: apt and apt-get Commands for Ubuntu/Debian Windows 11 Keyboard Shortcuts Cheat Sheet (Printable PDF) Cheat Sheets Windows 11 Keyboard Shortcuts Cheat Sheet (Printable PDF) Using scp on Linux – Securely transfer files Cheat Sheets Using scp on Linux – Securely transfer files

Leave a Comment

Press ESC to close