Commands · Reference

🐧Linux Commands

The sysadmin set, grouped by what you are trying to do rather than alphabetically — with the flags that actually get used.

Files & navigation

15 commands

Moving around and seeing what is there. ls -lh and find do most of the work; the rest is knowing which flag saves the second command.

CommandWhat it does Typical use
ls -lhtrLong listing, human sizes, oldest last — newest at the bottom where the cursor isls -lhtr /var/log
ls -ldaShow a directory's own entry rather than its contentsls -lda /etc/ssl
cd -Jump back to the previous directorycd -
pwd -PPhysical path, resolving symlinkspwd -P
tree -L 2 -dDirectory tree, two levels, directories onlytree -L 2 -d /opt
statInode, size, permissions and all three timestampsstat /etc/passwd
fileWhat a file actually is, by content not extensionfile /bin/ls
readlink -fResolve a symlink chain to its final targetreadlink -f $(which python3)
basename / dirnameSplit a path — useful in scriptsdirname /a/b/c.txt
cp -aArchive copy: preserves mode, owner, timestamps, linkscp -a /etc/nginx /backup/
mv -nMove without overwriting an existing targetmv -n a.log archive/
rsync -avh --progressCopy only what changed, with a progress barrsync -avh src/ dst/
rsync -avh --deleteMirror — removes files gone from the source. Dry-run firstrsync -avhn --delete a/ b/
ln -sSymbolic linkln -s /opt/app/current /usr/local/bin/app
shred -uOverwrite then remove — for keys on spinning disksshred -u secret.key

Permissions & ownership

12 commands

Numeric mode is three digits of read(4) write(2) execute(1). The fourth digit is setuid(4), setgid(2), sticky(1) — and the sticky bit on a shared directory is what stops users deleting each other's files.

CommandWhat it does Typical use
chmod 640Owner read/write, group read, others nothingchmod 640 /etc/app/secrets.conf
chmod u+x,g-wSymbolic form — change only what you namechmod u+x deploy.sh
chmod -R g+rXRecursive; capital X adds execute only to directorieschmod -R g+rX /srv/www
chmod 1777Sticky bit — only the owner can delete their own fileschmod 1777 /tmp
chmod 2775setgid on a directory — new files inherit the groupchmod 2775 /srv/shared
chown -R user:groupChange owner and group recursivelychown -R www-data:www-data /srv/www
umask 027Default mask for new files in this shellumask 027
getfacl / setfaclPer-user ACLs beyond the owner/group/other modelsetfacl -m u:deploy:rx /srv/app
lsattr / chattr +iImmutable flag — even root cannot modify until clearedchattr +i /etc/resolv.conf
sudo -lWhat can this user actually run as root?sudo -l -U deploy
idUID, GID and every supplementary groupid deploy
namei -lPermissions of every component in a path — finds the one bad directorynamei -l /srv/app/data/f

Text processing

19 commands

The pipeline tools. Worth knowing well: most log investigation is grep to narrow, awk to extract, sort | uniq -c to count.

CommandWhat it does Typical use
grep -rn --include='*.py'Recursive search with line numbers, one file typegrep -rn --include='*.py' TODO .
grep -c / -l / -vCount matches / list files only / invert the matchgrep -c ERROR app.log
grep -A3 -B3Show context lines after and before each hitgrep -A3 -B3 Traceback app.log
grep -P '\d{3}'Perl regex — the only way to get \d and lookaroundsgrep -oP 'status=\K\d+' access.log
awk '{print $7}'Print a field. The default separator is any run of whitespaceawk '{print $7}' access.log
awk -F: '$3>=1000{print $1}'Filter on a field with a custom separatorawk -F: '$3>=1000{print $1}' /etc/passwd
awk '{s+=$1} END{print s}'Sum a columndu -s * | awk '{s+=$1} END{print s}'
sed -i.bak 's/a/b/g'In-place replace, keeping a .bak. Always keep the backupsed -i.bak 's/8080/9090/g' app.conf
sed -n '100,120p'Print a line range without printing everything elsesed -n '100,120p' huge.log
sort -k2 -n -rSort by field 2, numeric, descendingsort -k2 -n -r sizes.txt
sort | uniq -c | sort -rnThe counting idiom — top offenders in any logawk '{print $1}' a.log | sort | uniq -c | sort -rn | head
cut -d, -f1,3Fields from delimited text, when awk is overkillcut -d, -f1,3 data.csv
tr -d '\r'Strip characters — this one fixes CRLF filestr -d '\r' < win.txt > unix.txt
tail -f / -FFollow a file; -F survives log rotationtail -F /var/log/app.log
head -n -5Everything except the last 5 lineshead -n -5 file.txt
wc -lLine countwc -l access.log
jq -r '.items[].name'Query JSON. -r drops the quoteskubectl get po -o json | jq -r '.items[].metadata.name'
column -tAlign whitespace-separated output into columnsmount | column -t
diff -u / vimdiffUnified diff between two filesdiff -u old.conf new.conf

Processes & signals

16 commands

A process is doing one of: running, waiting on I/O (D), sleeping (S), or already dead (Z). Which one it is decides where you look next.

CommandWhat it does Typical use
ps aux --sort=-%memEvery process, biggest memory firstps aux --sort=-%mem | head
ps -eo pid,ppid,stat,wchan:20,cmdState and the kernel function it is blocked inps -eo pid,stat,wchan:20,cmd
pgrep -afFind PIDs by pattern, showing the full command linepgrep -af nginx
pkill -f -TERMSignal by full-command-line match. Check with pgrep firstpkill -f -TERM 'python worker.py'
kill -TERM / -KILL15 asks politely, 9 cannot be caught or cleaned up afterkill -TERM 4412
kill -HUPReload config without a restart, for daemons that support itkill -HUP $(pidof nginx)
kill -lList signal names and numberskill -l
nice / reniceScheduling priority, -20 (highest) to 19renice 10 -p 4412
ionice -c3Idle I/O class — for backups that must not disturb productionionice -c3 rsync -a src/ dst/
nohup … &Survive the terminal closingnohup ./long-job.sh &
timeout 30sKill a command that runs too long. Use it in every cron jobtimeout 30s curl https://api/health
lsof -p PIDEvery file, socket and pipe a process holds openlsof -p 4412
lsof -i :8080Which process owns a portlsof -i :8080
fuser -vm /mntWho is using a mount point — before you unmountfuser -vm /mnt/data
strace -c -p PIDSyscall summary of a running processstrace -c -p 4412
pstree -pProcess tree with PIDs — shows who forked whompstree -p 1

Users, groups & sessions

12 commands

Account state lives in /etc/passwd, /etc/shadow and /etc/group. Everything below just edits those safely.

CommandWhat it does Typical use
useradd -m -s /bin/bashCreate a user with a home directory and a real shelluseradd -m -s /bin/bash deploy
useradd -r -s /usr/sbin/nologinSystem account that cannot log in — for servicesuseradd -r -s /usr/sbin/nologin appsvc
usermod -aGAdd to a group. Forget the -a and you replace every other groupusermod -aG docker deploy
userdel -rDelete the user and their home directoryuserdel -r olduser
passwd -l / -SLock an account / show its password statuspasswd -S deploy
chage -lPassword ageing and expiry for an accountchage -l deploy
groupadd / gpasswd -aCreate a group, add a membergpasswd -a deploy sudo
getent passwdQuery users through NSS — sees LDAP/SSSD, unlike grepping the filegetent passwd deploy
w / whoWho is logged in and what they are runningw
last -aLogin history from wtmplast -a | head
lastbFailed login attemptslastb | head
loginctl list-sessionssystemd's view of active sessionsloginctl list-sessions

Packages

11 commands

Three families. Know which one you are on before you type — /etc/os-release tells you.

CommandWhat it does Typical use
apt update && apt upgradeRefresh the index, then upgrade (Debian/Ubuntu)apt update && apt upgrade -y
apt list --installedWhat is installedapt list --installed | grep nginx
apt-cache policyInstalled version, candidate version, and which repoapt-cache policy nginx
dpkg -l / -L / -SList packages / files in a package / which package owns a filedpkg -S /usr/sbin/nginx
dnf install / updateRHEL 8+, Fedora, Rocky, Almadnf install -y nginx
dnf history / history undoTransaction log, and rolling one backdnf history undo last
rpm -qa / -ql / -qfQuery all / files in a package / owner of a filerpm -qf /usr/sbin/nginx
rpm -q --changelogWhy a version exists — includes the CVE it fixedrpm -q --changelog openssl | head
yum / zypper / apkRHEL 7 / SUSE / Alpine equivalentsapk add --no-cache curl
needs-restarting -rDoes this box need a reboot after patching? (RHEL)needs-restarting -r
ls /var/run/reboot-requiredSame question on Debian/Ubuntucat /var/run/reboot-required

Disk & filesystem

14 commands

Two different 'full' conditions: out of blocks (df -h) and out of inodes (df -i). Check both — millions of tiny files exhaust inodes first.

CommandWhat it does Typical use
df -h / -iFree space by blocks / by inodesdf -h; df -i
du -sh * | sort -hWhat is taking the space in this directorydu -sh * | sort -h | tail
du -xh --max-depth=1 /Top-level usage without crossing into other filesystemsdu -xh --max-depth=1 / | sort -h
lsblk -o NAME,SIZE,ROTA,MOUNTPOINTBlock devices, and whether they are rotationallsblk -o NAME,SIZE,ROTA,MOUNTPOINT
blkidUUIDs and filesystem types — what to put in /etc/fstabblkid /dev/sdb1
mount -o remount,rw /Remount read-write, e.g. in rescue modemount -o remount,rw /
findmntMounts as a tree, with the options actually in effectfindmnt /var
mkfs.ext4 / mkfs.xfsCreate a filesystemmkfs.xfs -L data /dev/sdb1
xfs_growfs / resize2fsGrow a filesystem after growing the volumexfs_growfs /data
fsck -nCheck without repairing. Never fsck a mounted filesystemfsck -n /dev/sdb1
pvs / vgs / lvsLVM at a glance — physical, group, logicalvgs; lvs
lvextend -r -L +50GGrow a logical volume and its filesystem in one steplvextend -r -L +50G /dev/vg0/data
iostat -x 1Per-device await and utilisation — is the disk the bottleneck?iostat -x 1
lsof +L1Deleted files still held open — why df and du disagreelsof +L1

Search & locate

10 commands

find is a query language. The order of predicates matters: it evaluates left to right and stops early, so put the cheap tests first.

CommandWhat it does Typical use
find . -name '*.log' -mtime +30Files matching a name, older than 30 daysfind /var/log -name '*.log' -mtime +30
find . -size +100MFiles over a sizefind / -xdev -size +100M 2>/dev/null
find . -type f -newer refChanged more recently than a reference filefind /etc -type f -newer /tmp/mark
find … -deleteDelete matches. Run it without -delete first, every timefind /tmp -name 'core.*' -mtime +7 -delete
find … -print0 | xargs -0Safe with spaces and newlines in filenamesfind . -name '*.gz' -print0 | xargs -0 rm
find … -exec … +One invocation for many files, not one per filefind . -name '*.c' -exec grep -l TODO {} +
find / -xdevStay on one filesystem — stops it wandering into /proc and NFSfind / -xdev -name core
find . -perm -4000setuid binaries — a standard audit sweepfind / -xdev -perm -4000 -ls
locate / updatedbInstant filename search from a prebuilt indexlocate nginx.conf
which / type -aWhere a command comes from; type -a shows aliases tootype -a ls

Scheduling & boot

8 commands

cron for wall-clock jobs, systemd timers for anything that needs dependencies, logging or a missed-run catch-up.

CommandWhat it does Typical use
crontab -l / -e / -uList, edit, or act on another user's crontabcrontab -l -u deploy
systemctl list-timers --allEvery timer, when it last ran and when it runs nextsystemctl list-timers --all
systemd-analyze blameWhich units made the boot slowsystemd-analyze blame | head
systemd-analyze critical-chainThe dependency path that determined boot timesystemd-analyze critical-chain
at now + 1 hourOne-off scheduled commandecho 'systemctl restart app' | at now + 1 hour
run-parts --testWhat would /etc/cron.daily actually run?run-parts --test /etc/cron.daily
uptime / who -bHow long since boot, and when it bootedwho -b
last rebootReboot historylast reboot | head

Networking

15 commands

ifconfig, netstat and route are deprecated and missing on modern minimal images. The ip and ss equivalents are below.

CommandWhat it does Typical use
ip aInterfaces and addresses (replaces ifconfig)ip -br a
ip rRouting table (replaces route -n)ip r get 8.8.8.8
ip -s linkPer-interface counters, including errors and dropsip -s link show eth0
ss -tulpnListening TCP/UDP sockets with the owning process (replaces netstat)ss -tulpn
ss -sSocket summary — how many in each statess -s
ss -tan state time-wait | wc -lCount sockets in one statess -tan state time-wait | wc -l
dig +short / +traceDNS answer only / the full delegation pathdig +trace api.example.com
dig @1.1.1.1Ask a specific resolver — proves whether it is your resolverdig @1.1.1.1 example.com
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n'Status and timing without the bodycurl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://api/health
curl -v --resolve host:443:IPTest one backend directly, bypassing DNScurl -v --resolve api:443:10.0.1.5 https://api/
tcpdump -nni any port 443 -w f.pcapCapture to a file for Wiresharktcpdump -nni any port 443 -c 100
mtr -rwtraceroute and ping combined, in a reportmtr -rw 8.8.8.8
nc -zvIs the port open? The quickest connectivity test there isnc -zv db.internal 5432
ethtool -SNIC statistics — drops, errors, ring exhaustionethtool -S eth0 | grep -i drop
nft list rulesetFirewall rules (nftables; iptables-save on older systems)nft list ruleset
← CategoriesIndex