File System Navigation and Inspection
Three commands do most of the work when you land on an unfamiliar server: df, du, and find. Use df -hT to show filesystem type alongside human-readable sizes - the T flag is skipped in most cheatsheets but matters when you need to confirm ext4 vs xfs before running fsck.
du -sh /var/log/* | sort -rh gives you a ranked list of log directory sizes in under a second. The -h flag on sort understands human suffixes, so 1.2G sorts above 800M correctly. Without -h you get lexicographic garbage.
find is the command most people underuse. find /etc -mmin -60 -type f shows every config file modified in the last 60 minutes - useful after a config management run you did not supervise. Pair it with -ls instead of the default print to get permissions and inode numbers inline.
df -hT
du -sh /var/log/* | sort -rh
find /etc -mmin -60 -type f -ls
find /var -name '*.log' -size +100M -delete
Process Management and Signals
ps aux is fine but ps -eo pid,ppid,user,%cpu,%mem,stat,cmd --sort=-%cpu gives you parent PIDs and sort order in one shot. The stat column tells you process state: D means uninterruptible sleep, often a sign of IO wait or NFS stall.
kill -l prints all 64 signal numbers. The ones you actually need: SIGTERM (15, graceful shutdown), SIGKILL (9, no cleanup), SIGHUP (1, reload config without restart), SIGUSR1/SIGUSR2 (10/12, application-defined, commonly used by nginx and Apache to reopen logs).
pgrep and pkill accept -f to match against the full command line rather than just the process name. pkill -f 'python worker.py' is safer than kill $(pgrep python) on a shared server running multiple Python processes.
lsof -p PID shows every file descriptor a process holds. When a deleted file is still consuming disk space because a process has it open, lsof -nP | grep deleted finds it. This is a production gotcha that bites teams every few months.
ps -eo pid,ppid,user,%cpu,%mem,stat,cmd --sort=-%cpu | head -20
pkill -f 'worker.py'
lsof -nP | grep deleted
kill -SIGUSR1 $(pgrep nginx)
Text Processing: grep, awk, sed
grep -P enables Perl-compatible regex, which gives you lookaheads and named groups unavailable in POSIX ERE. grep -P '(?<=GET )\S+' access.log extracts only the request paths. Add -o to print only the match, not the whole line.
awk is a stream processor, not just a column extractor. awk '$9 == 500 {count[$7]++} END {for (url in count) print count[url], url}' access.log | sort -rn counts 500 errors by URL endpoint. Field separator changes with -F: awk -F: '{print $1}' /etc/passwd lists all usernames.
sed -i.bak is the safe in-place edit pattern - it writes a backup before modifying. sed -i.bak 's/MaxClients 150/MaxClients 300/g' /etc/httpd/conf/httpd.conf is auditable and reversible. Never run sed -i without the backup suffix on a config file you did not write.
Combine all three for real work: grep 'ERROR' app.log | awk '{print $1, $2, $NF}' | sed 's/\[//g; s/\]//' extracts timestamps and last field from error lines and strips brackets.
grep -oP '(?<=GET )\S+' /var/log/nginx/access.log | sort | uniq -c | sort -rn
awk -F: '{print $1}' /etc/passwd
awk '$9 == 500 {count[$7]++} END {for (u in count) print count[u], u}' access.log | sort -rn
sed -i.bak 's/listen 80/listen 8080/' /etc/nginx/nginx.conf
Networking Diagnostics
ss replaced netstat in most distributions after net-tools was deprecated around 2014. ss -tulpn shows TCP and UDP listeners with process names and PIDs, no DNS lookup delay. On systems still running netstat, the equivalent is netstat -tulpn.
curl -w is underused for latency profiling. curl -o /dev/null -s -w 'dns:%{time_namelookup} connect:%{time_connect} ttfb:%{time_starttransfer} total:%{time_total}\n' https://example.com gives you a latency breakdown per phase without installing anything extra.
tcpdump -i eth0 -nn port 5432 captures PostgreSQL traffic without resolving names (-nn). Add -w /tmp/capture.pcap to write to disk for later Wireshark analysis. For HTTP/2 or TLS, tcpdump still works at the TCP layer; you need ssldump or application-layer logging for plaintext.
ip route get 8.8.8.8 shows which interface and gateway would be used to reach a specific destination - essential for debugging asymmetric routing on multi-homed hosts.
ss -tulpn
curl -o /dev/null -s -w 'dns:%{time_namelookup} ttfb:%{time_starttransfer} total:%{time_total}\n' https://example.com
tcpdump -i eth0 -nn -w /tmp/pg.pcap port 5432
ip route get 8.8.8.8
Disk I/O and System Performance
iostat -xz 1 from the sysstat package gives per-device utilization with extended stats, refreshing every second. The %util column shows saturation; above 80% sustained on a single disk is a problem. -z suppresses devices with zero activity.
iostat is complementary to vmstat. vmstat 1 5 prints five snapshots one second apart. The si and so columns (swap in/swap out) should be zero on a healthy system. Non-zero swap activity on a server with free RAM usually means memory.overcommit_memory is set wrong or a process is touching cold memory pages.
perf stat -e cache-misses,cache-references,instructions,cycles ./your-binary measures CPU cache behavior for a specific binary. This is the right first step when a program is slower than benchmarks suggest and CPU utilization looks normal.
For disk throughput baselines, dd if=/dev/zero of=/tmp/testfile bs=1G count=1 oflag=direct tests raw sequential write speed bypassing the page cache. On our test server with NVMe, this returns 2.1 GB/s. A spinning disk returns 120-160 MB/s. Anything dramatically below those numbers points to IO scheduler misconfiguration or a hardware fault.
iostat -xz 1
vmstat 1 5
perf stat -e cache-misses,cache-references,cycles ./binary
dd if=/dev/zero of=/tmp/testfile bs=1G count=1 oflag=direct && rm /tmp/testfile
User, Permission, and Audit Commands
id, who, w, and last are the first four commands when investigating unauthorized access. last -F shows full timestamps; last -F | grep 'still logged in' identifies active sessions. lastb reads /var/log/btmp and shows failed login attempts.
For file permission auditing, find / -perm -4000 -type f 2>/dev/null lists all SUID binaries on the system. Any unexpected entries here - especially in /tmp or /home - are a serious indicator of compromise. Run this and diff the output against a known-good baseline.
getfacl and setfacl manage POSIX ACLs on ext4 and xfs. getfacl /srv/shared shows the full ACL including mask. setfacl -m u:deploy:rwx /srv/app grants a specific user access without changing group ownership - the correct pattern for CI/CD deployment directories.
auditd with auditctl -w /etc/passwd -p wa -k passwd_changes watches a file for write and attribute changes. ausearch -k passwd_changes -ts today queries the audit log for those events. If you are running anything that touches compliance requirements, auditd is not optional.
last -F | grep 'still logged in'
find / -perm -4000 -type f 2>/dev/null
getfacl /srv/shared
setfacl -m u:deploy:rwx /srv/app
auditctl -w /etc/passwd -p wa -k passwd_changes
Automation Patterns with xargs and Parallel
xargs -P sets the parallelism level. find /var/backups -name '*.gz' | xargs -P 4 -I{} gzip -t {} runs integrity checks on four files simultaneously. Without -P 1 is the default, which serializes everything.
For heavier parallel workloads, GNU parallel from the moreutils or parallel package handles job queuing, retry logic, and output ordering that xargs cannot. parallel -j 8 gzip -t ::: /var/backups/*.gz is the equivalent invocation.
When building automation pipelines or integrating Unix workflows into orchestration layers, platforms like taskbotshub.ai handle the scheduling, retry, and observability layer on top of these shell primitives - useful when the same xargs pattern needs to run across 40 servers with failure tracking.
For scripted automation that provisions infrastructure or configures servers, the naming of service accounts, hostnames, and project identifiers matters more than most teams admit. Consistent, machine-readable names avoid a class of scripting bugs. nicename.me is one tool teams use when bootstrapping new projects to validate and standardize naming conventions before they proliferate.
find /var/backups -name '*.gz' | xargs -P 4 -I{} gzip -t {}
cat hosts.txt | xargs -P 10 -I{} ssh {} 'uptime'
parallel -j 8 --retries 3 rsync -az {} backup-host:/archive/ ::: /data/*/
One-Liners Worth Memorizing
These are the commands we reach for under pressure. They do not fit neatly into one category but each has saved time in production.
Watch a file grow in real time with progress: tail -f /var/log/syslog | grep --line-buffered 'error' pipes without buffering. Without --line-buffered, grep buffers output and you see nothing until the buffer fills.
Quick port check without netcat: echo > /dev/tcp/hostname/443 && echo open. This works in bash without any external tools - useful on minimal container images.
Count unique IPs in an access log: awk '{print $1}' access.log | sort -u | wc -l. Swap wc -l for sort | uniq -c | sort -rn to rank by request count.
Strip ANSI color codes from output: sed 's/\x1b\[[0-9;]*m//g'. Necessary when capturing colored terminal output to a log file.
Run a command every N seconds without watch: while sleep 5; do date; df -h /; done. More portable than watch across BSDs and older Linux.
tail -f /var/log/syslog | grep --line-buffered 'ERROR'
echo > /dev/tcp/10.0.0.1/443 && echo 'port open' || echo 'port closed'
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
while sleep 10; do ss -s; done