20 Actually Useful Linux One-Liners (2026)
In this tutorial, you'll learn about 20 actually useful linux one. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Most Linux one-liner lists give you ls -la and grep -r. You already know those. This list covers the commands that solve actual sysadmin and development problems — disk emergencies, Process hunting, network debugging, and automation. Every one-liner here has saved me at least once on a Friday afternoon.
In this guide, you will learn 20 one-line Linux commands that solve real-world system administration and development problems. Each command is a complete, ready-to-use pipeline that you can type directly into your terminal or adapt for scripts. These are the commands that experienced sysadmins reach for when a server is running low on disk space, a Process needs to be killed immediately, or network connectivity needs to be diagnosed under pressure.
Process Management
Find the 10 largest files in a directory tree — find . -type f -exec du -sh {} + | sort -rh | head -10
This pipeline identifies the largest files consuming disk space in the current directory tree. The find . -type f command locates every regular file recursively. The -exec du -sh {} + option runs du on batches of files, computing the human-readable size of each one. The sort -rh command sorts the results in reverse numerical order with human-readable number support (K, M, G suffixes). Finally, head -10 keeps only the top 10 results.
The + in -exec ... {} + is important — it batches files together instead of running du once per file, which would be significantly slower. If you need to exclude specific directories like .git or node_modules, add -not -path './.git/*' before the -exec portion. For scanning the entire system, run sudo find / -type f -exec du -sh {} + 2>/dev/null | sort -rh | head -20 to suppress permission-denied errors.
# Find largest files excluding .git
find . -type f -not -path './.git/*' -exec du -sh {} + | sort -rh | head -10
# Find largest files modified in the last 30 days
find . -type f -mtime -30 -exec du -sh {} + | sort -rh | head -10
# Find largest directories instead of files
du -sh */ | sort -rh | head -10
Kill all processes by name — pkill -f "node app.js" or kill $(pgrep -f "node app.js")
The pkill command sends a signal to every Process matching the given pattern. The -f flag matches against the full command line, not just the Process name, so it catches processes launched with different arguments. By default, pkill sends SIGTERM (signal 15), which allows processes to clean up resources before exiting. To force kill immediately, add -9 to send SIGKILL.
The alternative form kill $(pgrep -f "node app.js") is useful when you want to see which processes will be affected before killing them. Run pgrep -f "node app.js" first to list the PIDs, verify they are correct, then wrap with kill. The -f flag in pgrep matches the full command line just like pkill. For case-insensitive matching, use -i with both commands.
# Kill all Chrome processes
pkill -f chrome
# Force kill all Python processes
pkill -9 -f "python3 script.py"
# Kill processes for a specific user
pkill -u username -f "node"
# List matching processes before killing
pgrep -f "nginx"
Show CPU and memory usage per Process, sorted — ps aux --sort=-%cpu | head (replace %cpu with %mem for memory)
The ps aux command displays all running processes with their CPU and memory usage. The --sort=-%cpu flag sorts by CPU usage in descending order, putting the most CPU-intensive processes at the top. The head command keeps only the header row and the top processes. To sort by memory instead, replace %cpu with %mem in the sort flag.
This one-liner is the fastest way to identify which Process is consuming excessive resources. When a server becomes unresponsive or an application slows down, run this command first. The %CPU column shows the percentage of CPU time used, and %MEM shows the percentage of physical RAM. The VSZ and RSS columns show virtual and resident memory usage in kilobytes.
# Top 10 processes by memory usage
ps aux --sort=-%mem | head -10
# Show processes with full command line, wider output
ps auxww --sort=-%cpu | head -10
# Show only processes for a specific user
ps aux --sort=-%cpu | grep "^username" | head -10
# Count total processes
ps aux | wc -l
Logs & Monitoring
Monitor a log file in real time with timestamps — tail -f app.log | while read line; do echo "$(date '+%H:%M:%S') $line"; done
This pipeline adds timestamp prefixes to each line of a log file as it is written. The tail -f app.log command follows the file in real time, outputting new lines as they are appended. The while read line loop reads each line, and the echo command prepends a timestamp from the date command before printing the original line content.
The default log timestamps from many applications are either absent or formatted in ISO 8601 which is hard to parse visually at a glance. Adding a wall-clock timestamp with seconds precision makes it easier to correlate log events with external monitoring alerts or user reports. Adjust the date format to include milliseconds with date '+%H:%M:%S.%3N' for high-precision profiling.
# Monitor with full date including milliseconds
tail -f app.log | while read line; do echo "$(date '+%Y-%m-%d %H:%M:%S.%3N') $line"; done
# Monitor and filter for ERROR lines with timestamps
tail -f app.log | grep --line-buffered ERROR | while read line; do echo "$(date '+%H:%M:%S') $line"; done
# Add log level coloring (requires terminal support)
tail -f app.log | while read line; do
case "$line" in
*ERROR*) color='31';;
*WARN*) color='33';;
*) color='0';;
esac
echo -e "\e[${color}m$(date '+%H:%M:%S') $line\e[0m]
done
Watch a command every N seconds — watch -n 2 'netstat -tulpn | grep :3000' — re-runs the command every 2 seconds with a clear screen.
The watch command repeatedly runs a given command and displays its output, clearing the screen between runs. The -n 2 flag sets the interval to 2 seconds. The command argument is passed as a single-quoted string to prevent shell expansion. Combining watch with netstat -tulpn lets you monitor port availability in real time while waiting for a service to start or stop.
The -d flag highlights differences between consecutive runs, making it easy to spot changes at a glance. The -t flag removes the header showing the interval and command, which is useful for embedding in monitoring dashboards. You can watch any command this way — disk usage, Process counts, network connections, or log file sizes.
# Watch disk usage with change highlighting
watch -n 5 -d 'df -h /'
# Watch process count for a specific pattern
watch -n 1 'ps aux | grep nginx | wc -l'
# Watch with timing header disabled, compact output
watch -n 2 -t 'ss -tulpn | wc -l'
# Watch a custom script
watch -n 10 'sh -c "echo Current time: $(date); echo Load: $(uptime)"'
Disk & Storage
Disk usage per directory, human-readable, top 10 — du -sh */ | sort -rh | head -10
This one-liner shows the total disk usage of each direct subdirectory in the current directory. The du -sh */ command computes the total size of every directory one level deep (*/ matches only directories), using human-readable format (-h summarizes total size). The sort -rh sorts them in reverse numerical order with human-readable number awareness, placing the largest directory first.
This is the fastest way to identify what is consuming disk space in a given area. Unlike the file-finding pipeline above, this command shows directory totals rather than individual file sizes. Run it in /home to see which users use the most space, or in /var to check logs and application data. For a full system scan, run sudo du -sh /* | sort -rh | head -10.
# Check with a specific depth
du -d 2 -h /var | sort -rh | head -10
# Include hidden directories (like .cache)
du -sh .[!.]* */ 2>/dev/null | sort -rh | head -10
# Export to file for analysis
du -sh */ | sort -rh > disk-usage-$(date +%F).txt
# Check with exclusions
du -sh */ --exclude=node_modules --exclude=.git | sort -rh | head -10
Count files per directory recursively — for d in */; do echo "$d: $(find "$d" -type f | wc -l)"; done
This shell loop iterates over every subdirectory, counts the number of regular files within each, and prints the results. The for d in */ construct matches each immediate subdirectory. For each one, find "$d" -type f lists every regular file recursively, and wc -l counts the lines (each file is one line). The echo command formats the output as dirname: count.
This is useful for understanding the distribution of files across a project or filesystem. A directory with thousands of files may indicate a problem like accumulated cache files, log rotation failures, or a directory being used as a queue. To sort the output by count, pipe the entire loop through sort -t: -k2 -rn.
# Count all entries (including directories and symlinks)
for d in */; do echo "$d: $(find "$d" | wc -l)"; done
# Sort by count descending
for d in */; do echo "$d: $(find "$d" -type f | wc -l)"; done | sort -t: -k2 -rn
# Count files by extension
for ext in js ts py json; do
echo "$ext: $(find . -name "*.$ext" -type f | wc -l)"
done
# Count files modified in the last 24 hours per directory
for d in */; do echo "$d: $(find "$d" -type f -mtime -1 | wc -l)"; done
Find files modified in the last 24 hours — find . -type f -mtime -1
The -mtime -1 flag finds files modified less than 1 day ago (within the last 24 hours). The -1 means "less than 1 day," while +1 would mean "more than 1 day ago," and 1 without a sign means "exactly 1 day ago." The -mtime flag measures in 24-hour increments from the current time, so -mtime -1 includes files modified in the past 24 hours regardless of calendar date.
This command is essential for checking what changed during a specific time window. When debugging a sudden behavior change, finding recently modified files helps identify the cause. Combine with -ls at the end for a detailed listing including permissions, size, and modification time. The -mmin -1440 alternative uses minutes instead of days for more precise intervals.
# Find files modified within the last hour
find . -type f -mmin -60
# Find files modified between 2 and 7 days ago
find . -type f -mtime +2 -mtime -8
# Find and list with detailed info
find . -type f -mtime -1 -ls
# Find recently modified files larger than 10MB
find . -type f -mtime -1 -size +10M
Network
Check which ports are listening — ss -tulpn (modern replacement for netstat)
The ss command provides socket statistics with faster performance and richer output than netstat. The flags decode as: -t for TCP sockets, -u for UDP sockets, -l for listening sockets only (not established connections), -p for showing the Process that owns each socket, and -n for numeric port numbers instead of service names.
The output shows the protocol, receive/transmit queues, local and peer addresses, and the Process name and PID. When a port shows as occupied that you expected to be free, the Process column identifies the culprit immediately. For established connections rather than listeners, omit the -l flag. To check for connections to a specific port, pipe through grep :3000.
# Show only TCP listening ports
ss -tln
# Show all connections (not just listeners)
ss -tulpn
# Filter by port number
ss -tulpn | grep :80
# Show established connections with process info
ss -tupn state established
# Show connection summary
ss -s
Get your external IP — curl -s ifconfig.me or curl -s icanhazip.com
These services return your public IP address as seen by the internet, without any HTML formatting or extra content. The curl -s flag runs in silent mode to hide the progress bar and error output. The services ifconfig.me, icanhazip.com, api.ipify.org, and checkip.amazonaws.com all serve the same purpose with different reliability and latency characteristics.
For scripting, use ifconfig.me as it returns only the IP address with no trailing newline issues. For IPv6 support, use curl -6 ifconfig.me. For geolocation data in JSON format, use curl -s ipinfo.io which returns IP, location, ISP, and ASN in a single query.
# Get public IP address
curl -s ifconfig.me
# Get IPv6 address specifically
curl -s -6 icanhazip.com
# Get IP with geolocation details
curl -s ipinfo.io
# Get IP and log to file with timestamp
echo "$(date): $(curl -s ifconfig.me)" >> ip-history.txt
Check SSL certificate expiry date — echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
This pipeline connects to an HTTPS server, retrieves the SSL/TLS certificate, and displays the validity dates. The openssl s_client -servername example.com -connect example.com:443 establishes a TLS connection using SNI (Server Name Indication) to specify the hostname. The 2>/dev/null suppresses diagnostic output. The second openssl x509 -noout -dates command extracts and displays the notBefore and notAfter dates from the certificate.
Set up a cron job using this command to receive email alerts when certificates are approaching expiry. The -checkhost option in newer OpenSSL versions provides a simpler interface. For JSON output, use the -text | grep -E "Not Before|Not After" variants and parse the results.
# Check a specific port (e.g., 8443)
echo | openssl s_client -servername example.com -connect example.com:8443 2>/dev/null | openssl x509 -noout -dates
# Check and calculate days until expiry
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2
# Check multiple domains from a file
while read domain; do
echo -n "$domain: "
echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null || echo "Failed"
done < domains.txt
Download an entire website recursively — wget --mirror --page-requisites --convert-links --no-parent -e robots=off -P ./site https://example.com
This wget command creates a fully offline copy of a website. The --mirror flag enables recursive download with timestamp preservation. --page-requisites downloads CSS, JavaScript, and images required for each page to render. --convert-links rewrites the HTML links to work locally. --no-parent prevents downloading from parent directories (keeping the download contained). -e robots=off ignores robots.txt restrictions. -P ./site specifies the output directory.
Use this to create offline documentation archives, backup personal websites, or audit a site's structure. Be aware that downloading entire sites can generate significant traffic — respect the site's robots.txt unless you have explicit permission, and limit the download rate with --limit-rate=1m to avoid overwhelming the server.
# Download with rate limiting
wget --mirror --page-requisites --convert-links --limit-rate=1m -e robots=off -P ./site https://example.com
# Download only HTML files (no assets)
wget --mirror --accept html -P ./site https://example.com
# Download specific directory only
wget --recursive --no-parent -P ./docs https://example.com/docs/
# Download with authentication
wget --mirror --user=username --password=secret -P ./site https://example.com
File Operations
Bulk rename files (replace spaces with underscores) — for f in *\ *; do mv "$f" "${f// /_}"; done
This loop renames all files in the current directory that contain spaces, replacing each space with an underscore. The for f in *\ * pattern matches every filename that contains a space (the backslash escapes the space in the glob pattern). The mv "$f" "${f// /_}" construction uses bash's parameter expansion to replace all spaces with underscores in the new filename.
The double-quoting of both $f and the expansion is critical — without quotes, filenames with multiple spaces would be split into separate arguments. Test the command first by replacing mv with echo to see which files would be renamed and what their new names would be. For dry runs: for f in *\ *; do echo mv "$f" "${f// /_}"; done.
# Dry run (preview changes)
for f in *\ *; do echo mv "$f" "${f// /_}"; done
# Rename replacing multiple characters
for f in *; do mv "$f" "${f//[ ()]/_}"; done
# Convert to lowercase
for f in *; do mv "$f" "$(echo "$f" | tr '[:upper:]' '[:lower:]')"; done
# Add prefix to all files
for f in *; do mv "$f" "backup_$f"; done
# Rename extensions
for f in *.htm; do mv "$f" "${f%.htm}.html"; done
Extract tar.gz to a directory — tar -xzf archive.tar.gz -C /target/directory
The tar command extracts an archive to a specific directory. The flags decode as: -x for extract, -z for gzip decompression (auto-detected in newer versions), -f for the archive filename. The -C flag changes to the target directory before extracting, keeping the extracted files organized.
Always use the -C flag to specify a target directory rather than extracting in the current directory and moving files afterward. This prevents the extracted contents from scattering across your working directory. To view archive contents without extracting, use tar -tzf archive.tar.gz. For tar.bz2 files, replace -z with -j, or let tar auto-detect the compression with no flag.
# View contents without extracting
tar -tzf archive.tar.gz
# Extract .tar.bz2
tar -xjf archive.tar.bz2 -C /target
# Extract .tar.xz
tar -xJf archive.tar.xz -C /target
# Extract specific files from archive
tar -xzf archive.tar.gz -C /target file1.txt path/to/file2.txt
Find text in files, excluding node_modules — grep -r --exclude-dir=node_modules --exclude-dir=.git "search_term" .
This recursive grep searches through the current directory tree but skips the node_modules and .git directories. The --exclude-dir flag accepts a directory name pattern and can be specified multiple times to exclude multiple directories. The -r flag enables recursive search. Without these exclusions, grep would search through every file in node_modules, which can contain hundreds of thousands of files and take minutes to complete.
For better performance, use ripgrep (rg) which respects .gitignore and other ignore files automatically: rg "search_term" .. Ripgrep is typically 5-10x faster than grep for codebase searches. If grep is the only available tool, the --exclude-dir flag combined with --include="*.py" (to search only specific file types) provides the best balance of speed and coverage.
# Exclude multiple directories
grep -r --exclude-dir={node_modules,.git,dist,build} "search_term" .
# Search only specific file types
grep -r --include="*.py" --include="*.js" "search_term" .
# Show only filenames with matches
grep -rl --exclude-dir=node_modules "search_term" .
# Show context lines around each match
grep -r --exclude-dir=node_modules -C 3 "search_term" .
Rsync with progress bar — rsync -avh --progress /source/ /destination/
rsync is a fast, versatile file copying tool that transfers only the differences between source and destination. The -a flag enables archive mode (preserves permissions, timestamps, symbolic links, and other metadata), -v enables verbose output, and -h makes file sizes human-readable. The --progress flag shows per-file transfer progress with transfer speed and estimated time remaining.
The trailing slash on the source directory is significant. rsync -a /source/ /dest/ copies the contents of /source into /dest, while rsync -a /source /dest/ copies the /source directory itself into /dest. Always use the trailing slash on the source when you want to copy the directory contents without creating an extra nesting level.
# Dry run to see what would be transferred
rsync -avh --dry-run --progress /source/ /destination/
# Copy over SSH (preserve remote path)
rsync -avh --progress -e ssh user@host:/source/ /local/destination/
# Delete files at destination that no longer exist at source
rsync -avh --delete --progress /source/ /destination/
# Exclude specific patterns
rsync -avh --progress --exclude='node_modules' --exclude='.git' /source/ /destination/
# Resume interrupted transfer
rsync -avh --partial --progress /source/ /destination/
System Info & Security
List all users on the system — cut -d: -f1 /etc/passwd
The /etc/passwd file contains one line per user account, with seven colon-separated fields: username, password placeholder, UID, GID, GECOS (full name), home directory, and login shell. The cut -d: -f1 command extracts the first field (username) from each line. This returns every user account on the system, including system accounts created by installed packages.
To distinguish between human users and system accounts, check the UID range. Most Linux distributions reserve UIDs below 1000 for system accounts. Use awk -F: '{if ($3 >= 1000) print $1}' /etc/passwd to list only human users. For users who can log in, check that their shell is not /sbin/nologin or /bin/false: grep -v '/sbin/nologin\|/bin/false' /etc/passwd | cut -d: -f1.
# List only human users (UID >= 1000)
awk -F: '{if ($3 >= 1000) print $1}' /etc/passwd
# List users with login capability
grep -v '/sbin/nologin\|/bin/false\|/usr/bin/nologin' /etc/passwd | cut -d: -f1
# List users with their UID and GID
awk -F: '{print $1, $3, $4}' /etc/passwd | column -t
# List currently logged-in users
who | awk '{print $1}' | sort -u
Dump full system information — uname -a && lscpu && free -h && df -h
This pipeline chains four commands to output a comprehensive system overview. uname -a shows the kernel name, hostname, kernel release, kernel version, machine hardware, and operating system. lscpu provides CPU architecture, core count, thread count, model name, and cache sizes. free -h displays memory and swap usage in human-readable format. df -h shows disk space usage for all mounted filesystems.
Run this command when you first SSH into an unfamiliar server to understand its hardware and current resource state. The output provides all the information needed to make deployment decisions: available memory, disk space, CPU cores, and kernel version. For integration with monitoring systems, put each command in a separate script and parse the output programmatically.
# Add disk I/O and network info
uname -a && echo "---CPU---" && lscpu && echo "---MEM---" && free -h && echo "---DISK---" && df -h && echo "---NET---" && ip addr show | grep inet
# Save to a file for record-keeping
uname -a | tee system-info-$(date +%F).txt
# Script-friendly version (one line per metric)
echo "kernel=$(uname -r) cpus=$(nproc) mem=$(free -h | grep Mem | awk '{print $2}')"
Check system uptime and load — uptime — shows how long since last reboot, number of users, and 1/5/15 minute load averages.
The uptime command displays the current time, how long the system has been running, how many users are currently logged in, and the system load averages for the past 1, 5, and 15 minutes. The load average represents the number of processes waiting to run — a value equal to the number of CPU cores indicates full utilization. Values consistently above the core count suggest the system is overloaded.
A high 1-minute load average with lower 5- and 15-minute averages indicates a recent spike in activity. Consistently high load at all three intervals indicates a sustained overload that needs investigation. Use nproc to find the number of CPU cores, then compare against the load averages. Load of 8 on a 4-core machine means the CPU queue is twice as long as the hardware can handle.
# Display in a more readable format
uptime -p
# Show since timestamp instead of duration
uptime -s
# Monitor load over time
while true; do uptime >> load-history.log; sleep 60; done
# Alert if load exceeds threshold
load=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
if (( $(echo "$load > 4.0" | bc -l) )); then
echo "High load alert: $load"
fi
Generate a random 32-character password — openssl rand -base64 24
The openssl rand -base64 24 command generates 24 random bytes and encodes them in base64, producing a 32-character string. Base64 encoding converts 3 bytes into 4 characters, so 24 bytes produce 32 characters. The output contains uppercase letters, lowercase letters, digits, and two symbols (+ and /), making it suitable for API keys and database passwords.
For passwords that must work in URLs without encoding, strip the symbols using tr -d '+/' or use openssl rand -hex 16 for a 32-character hex string (0-9, a-f). For human-readable passwords, use apg or pwgen which generate pronounceable passwords. Always use a secure random source (/dev/urandom) rather than a predictable algorithm.
# Generate a 64-character random string
openssl rand -base64 48
# Generate hex string (alphanumeric only)
openssl rand -hex 16
# Generate with special characters removed
openssl rand -base64 24 | tr -d '+/='
# Generate multiple passwords at once
for i in {1..5}; do openssl rand -base64 12; done
# Generate a numeric PIN (6 digits)
openssl rand -hex 3 | tr 'a-f' '0-9' | head -c 6
Practice Questions
- Write a one-liner that finds the 5 largest directories in
/varsorted by size. - How would you check which Process is listening on port 3000 without using netstat?
- Write a one-liner to rename all
.htmfiles in the current directory to.html. - How do you find all files modified in the last 24 hours that are larger than 100MB?
- Write a one-liner that outputs the system's kernel version, total memory, and disk usage of the root filesystem in a single command.
Answers
sudo du -sh /var/* | sort -rh | head -5ss -tulpn | grep :3000— the Process column shows the PID and Process name.for f in *.htm; do mv "$f" "${f%.htm}.html"; donefind . -type f -mtime -1 -size +100Mecho "Kernel: $(uname -r) Memory: $(free -h | grep Mem | awk '{print $2}') Root: $(df -h / | tail -1 | awk '{print $3}')"
Mini Project: Build a System Health Report Script
Create a bash script that generates a timestamped HTML report of the system's current health using these one-liners. The script should capture the output of uptime, free -h, df -h, ss -tulpn, and the top 5 CPU-consuming processes. Format the output with HTML headers and
tags for the command output. Schedule the script with cron to run every hour and serve the reports via a simple HTTP server.#!/bin/bash # system-report.sh — generate HTML system health report REPORT_DIR="/var/www/reports" TIMESTAMP=$(date '+%Y%m%d-%H%M%S') cat > "$REPORT_DIR/report-$TIMESTAMP.html" <<EOF <html><head><title>System Report $TIMESTAMP</title></head><body> <h1>System Health Report</h1> <p>Generated: $(date)</p> <h2>Uptime & Load</h2> <pre>$(uptime)</pre> <h2>Memory Usage</h2> <pre>$(free -h)</pre> <h2>Disk Usage</h2> <pre>$(df -h)</pre> <h2>Listening Ports</h2> <pre>$(ss -tulpn)</pre> <h2>Top 5 CPU Processes</h2> <pre>$(ps aux --sort=-%cpu | head -6)</pre> </body></html> EOF # Keep only latest 10 reports ls -t "$REPORT_DIR"/report-*.html | tail -n +11 | xargs rm -f 2>/dev/null
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro