Updated: 8 October 2026 · Applies to: Debian 13, Ubuntu 24.04 and 26.04, Rocky Linux 9 (GNU coreutils 8.32 to 9.7, uutils coreutils 0.10.0 on Ubuntu 26.04, GNU grep 3.6 to 3.12, GNU diffutils 3.10 and 3.12)
Linux has a small set of commands for searching, sorting, counting and changing text in files. Each one does one job, and you chain them with a pipe (|):
grep 'text' file # lines that contain text sort file # sort lines sort file | uniq -c # count repeated lines wc -l file # count lines cut -d' ' -f1 file # first field of each line tr 'a-z' 'A-Z' < file # replace or delete characters diff -u old new # show what changed between two files
None of these commands changes the file; they print the result. Most examples below use a 10-line web server access log whose lines look like this:
203.0.113.7 - - [07/Oct/2026:21:00:01 +0000] "GET / HTTP/1.1" 200 5120 198.51.100.23 - - [07/Oct/2026:21:00:04 +0000] "GET /wp-login.php HTTP/1.1" 404 162
grep: find lines that match
$ grep ' 404 ' access.log 198.51.100.23 - - [07/Oct/2026:21:00:04 +0000] "GET /wp-login.php HTTP/1.1" 404 162 198.51.100.23 - - [07/Oct/2026:21:01:15 +0000] "GET /.env HTTP/1.1" 404 162 198.51.100.23 - - [07/Oct/2026:21:01:16 +0000] "GET /xmlrpc.php HTTP/1.1" 404 162 $ grep -c ' 404 ' access.log 3
-iignores case,-vshows the lines that do not match,-nadds line numbers,-ccounts matching lines.-wmatches whole words only:grep web1 servers.txtalso foundweb10,grep -w web1did not.-Eallows alternatives:grep -E '" (403|500) ' access.logfinds both status codes.-A 2,-B 2and-C 2show 2 lines after, before or around each match.-Fsearches for the text literally. Without it the pattern is a regular expression, where.means any character:grep '.env'also matched/xenv,grep -F '.env'did not.
Exit status 0 means a match, 1 no match, 2 an error such as a missing file. To search a whole folder, see find files containing text with grep -r; for egrep and fgrep, see grep, egrep and fgrep.
sort: put lines in order
sort compares text character by character, so numbers need -n. With -k2 it sorts on the second field (fields are separated by blanks, or by the character after -t):
$ sort -k2 servers.txt web1 16 cache1 2 db1 32 web10 4 web2 8 $ sort -k2 -n servers.txt cache1 2 web10 4 web2 8 web1 16 db1 32
-rreverses,-udrops duplicate lines,-t';'sets the field separator for CSV files.-hunderstands sizes such as48K,512Mand1.2G, sodu -sh * | sort -hlists folders from small to large.-Vsorts names with numbers naturally:web1,web2,web10.
uniq: remove or count repeated lines
uniq only compares each line with the one before it, so always sort first. On the unsorted file uniq -c counted every line as 1:
$ sort fruit.txt | uniq -c
2 apple
3 banana
1 cherry
$ sort fruit.txt | uniq -c | sort -rn
3 banana
2 apple
1 cherry
uniq -d prints only the lines that repeat, uniq -u only the lines that appear once.
wc: count lines, words and bytes
$ wc access.log 10 100 783 access.log $ wc -l access.log fruit.txt 10 access.log 6 fruit.txt 16 total $ wc -l < access.log 10
The three numbers are lines, words and bytes. -l, -w and -c print one of them, -m counts characters (different from bytes in UTF-8 text). Reading the file with < prints the number without the file name, which is handy in scripts.
cut: take columns out of each line
$ cut -d' ' -f1 access.log | head -3 203.0.113.7 198.51.100.23 203.0.113.7 $ cut -d';' -f1,3 customers.csv id;plan 101;vps-lite 102;vps-pro
-d sets the separator (one character) and -f the fields; -c1-11 cuts by character position instead. cut -d: -f1,7 /etc/passwd lists each user with their login shell. cut treats every separator as a new field, so two spaces in a row give an empty field: printf 'a b\n' | cut -d' ' -f2 printed an empty line. Squeeze the spaces first with tr -s ' ', or use awk, which splits on any run of blanks.
tr: replace, squeeze or delete characters
$ echo 'Hello World' | tr 'a-z' 'A-Z' HELLO WORLD $ echo 'phone: +91 98470 12345' | tr -cd '0-9\n' 919847012345
A common server use is removing Windows line endings (\r) from a file uploaded from a PC; cat -A shows them as ^M:
$ cat -A windows.conf server_name example.com;^M$ root /var/www/html;^M$ $ tr -d '\r' < windows.conf > unix.conf && cat -A unix.conf server_name example.com;$ root /var/www/html;$
tr reads only standard input: tr 'a-z' 'A-Z' fruit.txt fails with tr: extra operand 'fruit.txt'. More examples in tr command examples.
diff: compare two files
$ diff -u nginx.old nginx.new --- nginx.old 2026-10-08 05:09:28.804454557 +0000 +++ nginx.new 2026-10-08 05:09:28.804454557 +0000 @@ -1,4 +1,5 @@ -worker_processes 2; +worker_processes auto; keepalive_timeout 65; -client_max_body_size 8m; +client_max_body_size 64m; gzip on; +server_tokens off;
Lines starting with - are only in the first file, + only in the second; the rest is unchanged context. diff -q just says Files nginx.old and nginx.new differ. The exit status is 0 for identical files, 1 for different, 2 for trouble. Before editing a config, keep a copy (cp site.conf site.conf.bak) so you can diff it afterwards. For folders and other tools, see compare files and directories with diff, cmp and vimdiff. If diff is not installed (it was missing in the minimal Rocky Linux 9 and AlmaLinux 10 images we tested), install it with dnf install diffutils.
Put them together
Which IP addresses made the most requests, and which status codes did the server return?
$ awk '{print $1}' access.log | sort | uniq -c | sort -rn
4 203.0.113.7
4 198.51.100.23
2 192.0.2.55
$ awk '{print $9}' access.log | sort | uniq -c | sort -rn
5 200
3 404
1 500
1 403
$ awk '$9 == 404 {print $7}' access.log
/wp-login.php
/.env
/xmlrpc.php
awk numbers the blank-separated fields of each line ($1 is the IP, $7 the path, $9 the status). To replace text in a file, use sed, for example sed 's/old/new/g' file (see sed options and usage).
Common mistakes
sort file > fileempties the file. The shell truncates it beforesortreads it; in our testwc -lthen reported 0 lines. Usesort -o file file.- Running
uniqwithoutsort, or sorting numbers without-n, as shown above. - Different sort order on another server. The order depends on the locale. With
en_US.UTF-8,sortprintedapple Apple _backup banana Cherry; withLC_ALL=Cit printedApple Cherry _backup apple banana(byte order). PutLC_ALL=Cin front ofsortin scripts that must give the same result everywhere. - Special characters in grep patterns. Quote the pattern, and use
-Ffor literal text such as IP addresses or file names.
Ubuntu 26.04 note
On Ubuntu 26.04, sort, uniq, wc, cut, tr and paste come from uutils coreutils 0.10.0 (the Rust rewrite). Every example in this article gave the same output as GNU coreutils 9.7 on Debian 13, with one exception: sort -f (ignore case) under en_US.UTF-8 printed Apple apple banana Cherry _backup, where GNU printed apple Apple _backup banana Cherry. grep, sed, awk and diff are separate packages and are not affected.
Related: list files with ls, display file contents with cat, less, head and tail and wildcards and globbing.
Ucartz services for this topic
- KVM VPS hosting: NVMe SSD and full root access, with Free Basic Managed Support.
- Unmanaged dedicated servers: full root access and free IPMI KVM, with Free Basic Managed Support.
- Linux server management: hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.
