Linux
find, grep, sed and awk Cheat Sheet
Practical recipes for find, grep, sed and awk: find large or old files, search logs, replace text across files, sum columns, and combine them in one-liners
Updated November 6, 2026 · Applies to GNU findutils · GNU grep · GNU sed · GNU awk · Ubuntu · Debian · RHEL / Rocky / AlmaLinux
find: by name and type
find . -name '*.log' # by name (quote the pattern)find . -iname 'readme*' # ignore casefind /etc -type f -name '*.conf' # files onlyfind . -type d -name node_modules # folders onlyfind . -maxdepth 2 -name '*.yml' # not too deepfind . -path ./node_modules -prune -o -name '*.js' -print # skip a folderfind: by size and time
find /var -type f -size +100M # bigger than 100 MBfind / -xdev -type f -size +1G 2>/dev/null # on this disk onlyfind /var/log -type f -mtime +30 # changed over 30 days agofind . -type f -mmin -60 # changed in the last hourfind . -type f -empty # empty filesfind . -newer reference.txt # newer than a filefind: by owner and permissions
find /srv -user root # owned by rootfind /srv ! -user www-data # not owned by www-datafind . -type f -perm 777 # exactly 777find . -type f -perm -o+w # writable by anyonefind . -type f -perm /111 # executable by someoneThe chmod Calculator explains those numbers.
find: act on the results
find . -name '*.tmp' -delete # delete (test without -delete first)find . -type f -name '*.sh' -exec chmod +x {} + # one command, many filesfind . -type f -exec grep -l 'TODO' {} + # files containing a wordfind . -type d -exec chmod 755 {} + # folders onlyfind . -name '*.log' -print0 | xargs -0 gzip # safe with spaces in namesfind . -type f -printf '%s %p\n' | sort -n | tail # largest filesFor a huge number of files, this avoids Argument list too long.
grep: search
grep 'error' app.log # lines containing itgrep -i 'error' app.log # ignore casegrep -v 'debug' app.log # lines NOT containing itgrep -n 'error' app.log # with line numbersgrep -c 'error' app.log # how many linesgrep -w 'cat' file # whole word onlygrep -F '1.2.3.4' file # plain text, not a patterngrep: more
grep -r 'listen 80' /etc/nginx/ # in a foldergrep -rl 'old-name' . # only the file namesgrep -rn --include='*.py' 'import os' . # only some filesgrep -r --exclude-dir=.git 'TODO' . # skip a foldergrep -A3 -B1 'error' app.log # 3 lines after, 1 beforegrep -C2 'error' app.log # 2 lines aroundgrep -E 'error|fatal' app.log # either one (extended regex)grep -E '^[0-9]{4}-' app.log # lines starting with a yeargrep -o 'id=[0-9]*' app.log # only the matching partgrep -P '\d+\.\d+' file # Perl regex, with \d and lookaroundPlain grep doesn’t know \d, + or | the way you may expect, so use -E, or -P for Perl syntax. For matching IP addresses, ports or dates, test your pattern first.
sed: replace
sed 's/old/new/' file # first on each line (prints; file unchanged)sed 's/old/new/g' file # all on each linesed -i 's/old/new/g' file # change the filesed -i.bak 's/old/new/g' file # keep a backup as file.baksed 's#/usr/local#/opt#g' file # another delimiter, for pathssed -E 's/([0-9]+)-([0-9]+)/\2-\1/' file # groups (extended regex)sed -i 's/\r$//' file # Windows line endings to LinuxOn macOS, -i needs an argument: sed -i '' 's/old/new/g' file.
Across many files:
grep -rl 'old-name' src/ | xargs sed -i 's/old-name/new-name/g'find . -name '*.conf' -exec sed -i 's/8080/9090/g' {} +sed: lines
sed -n '10,20p' file # print lines 10 to 20sed '5d' file # delete line 5sed '/^#/d' file # delete comment linessed '/^$/d' file # delete empty linessed '/pattern/d' file # delete matching linessed -n '/start/,/end/p' file # print between two patternssed '1i\# header' file # insert before line 1sed '$a\last line' file # add after the last lineawk: columns
awk '{print $1}' file # first columnawk '{print $NF}' file # last columnawk '{print $1, $3}' file # two columnsawk -F: '{print $1}' /etc/passwd # another separatorawk -F, '{print $2}' data.csv # simple CSV, with no quoted commasawk 'NR>1' file # skip the headerawk 'NR==5' file # only line 5awk 'NF' file # skip empty linesawk: filter and calculate
awk '$3 > 100' file # where column 3 is over 100awk '$1 == "GET"' access.log # where column 1 equals GETawk '/error/ {print $2}' app.log # column 2 of matching linesawk '{s += $3} END {print s}' file # sum of a columnawk '{s += $3} END {print s/NR}' file # averageawk '{c[$1]++} END {for (k in c) print c[k], k}' file # count by valueTogether
# the 10 IP addresses with the most requestsawk '{print $1}' access.log | sort | uniq -c | sort -nr | head -n 10
# status codes in an nginx logawk '{print $9}' access.log | sort | uniq -c | sort -nr
# errors per hourgrep -i error app.log | cut -c1-13 | sort | uniq -c
# the biggest folders heredu -xh --max-depth=1 . | sort -h | tail -n 10
# all listening ports, as numbersss -tln | awk 'NR>1 {print $4}' | sed 's/.*://' | sort -unPractice, and related errors
- Try
find,grepandsedin the Linux terminal, where you can’t break anything. It doesn’t haveawkyet. No space left on deviceArgument list too long- Linux Troubleshooting Cheat Sheet
Practice these
Guided lessons, in your browser: grep, pipes and redirects, sort and uniq, sed and find.