Regex in Linux: Practical Tips for grep, sed and AWK

You’re staring at a log file with thousands of lines, and you need every line where a request timed out. Or you have to rename a config value across 40 files before a deploy. Scrolling and copy-pasting won’t cut it. This is where regex earns its keep.

Regex (short for regular expressions) is a way to describe a text pattern so a tool can find, replace or pull out matching text for you. In this post, I’ll show you the regex basics you need and how to use them in Linux with the three tools you’ll reach for most: grep, sed and AWK.

Which tool to use for regex in Linux

Use grep to find lines, sed to change text, and AWK to pull out fields. All three read text line by line and accept regex patterns, so once you know the symbols below, you can switch between them easily.

ToolUse it toTypical job
grepFind matching linesShow every timeout in a log
sedReplace matching textRename a config value across files
AWKExtract fields from matching linesPrint one column from a log or CSV

Regex basics you need first

A regular expression is a string of normal characters and special symbols that together describe a pattern in text. You’ll use the same handful of symbols over and over, so learn these first:

  • . (dot) matches any single character.
  • * (asterisk) matches zero or more of the character before it.
  • + (plus) matches one or more of the character before it.
  • [ ] (brackets) match any single character inside them, like [0-9] for one digit.
  • ^ (caret) matches the start of a line.
  • $ (dollar sign) matches the end of a line.

One gotcha: in plain grep, + is treated as a literal plus sign. Add the -E flag (extended regex) and it works as described above. For example, to find lines that start with ERROR and end with timeout, run:

grep -E '^ERROR.+timeout$' app.log

The ^ and $ anchor the match to the whole line, and .+ means “at least one character of anything” in between.

Search for regex patterns with grep

grep searches a file line by line and prints every line that matches your regex. It’s the tool you’ll use most often with regex in Linux. Give it the pattern first, then the file:

grep "pattern" file.txt

If you search through a lot of output, grep pairs nicely with an interactive filter. I’d suggest setting up fzf with Zsh for faster terminal search so you can narrow results as you type. Working with Kubernetes? You can pipe pod logs from a tool like stern straight into grep, as I show in my post on Kubernetes CLI tools I use to manage clusters faster.

Replace text with sed and regex

sed (stream editor) finds text that matches a regex and replaces it with new text. It’s great for editing big files and scripting repetitive changes. Give it the pattern to find and the text to put in its place:

sed "s/pattern/replacement/g" file.txt

Run sed without the -i flag first. That way, sed prints the result to your screen instead of changing the file, and you can check the output before you commit to it.

Extract fields with AWK and regex

AWK reads a file line by line, matches lines against a regex, and runs an action on them, like printing a certain column. Use AWK when you need specific fields, rows or columns from structured text such as logs or CSV files. Give it the pattern and the action:

awk '/pattern/ {action}' file.txt

Make complex regex easier to read

Long regex patterns get hard to read fast, especially when you stack groups and repeats. Perl-compatible regular expressions (PCRE, now maintained as PCRE2) add handy shortcuts like \d for a digit, which keeps patterns shorter. GNU grep can use them with the -P flag. To find three digits in a row, run:

grep -P '\d{3}' file.txt

The same search in basic syntax would be [0-9][0-9][0-9], so you can see why the shortcut helps. Your future self, reading this pattern at 2 a.m. during an incident, will thank you.

Handy regex patterns for DevOps work

Here are some regex patterns I find useful for everyday DevOps tasks:

# IP Address:
\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

# Email address
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b

# URL
(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])

# Date (YYYY-MM-DD)
\b\d{4}[-\/]\d{2}[-\/]\d{2}\b

# Time (HH:MM:SS):
\b(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\b

# Unix timestamp:
\b[0-9]+\b

If you live in the terminal like I do, these work even better with a split pane open on your logs. My guide to tmux for terminal management shows how to set that up.

Hope this saves you some time on your next log hunt. 🔍 For more shell shortcuts, check out these helpful Linux commands.

Frequently asked questions

What is the difference between grep and grep -E?

Plain grep uses basic regular expressions, where symbols like + and ? are treated as literal characters unless you escape them. grep -E switches to extended regular expressions, so those symbols work as special operators without backslashes. If a pattern with + finds nothing, adding -E is the first thing to try.

How do I make a grep regex search case-insensitive?

Add the -i flag to grep, for example grep -i 'error' app.log. It matches ERROR, Error and error alike. You can combine it with other flags, like grep -Ei for a case-insensitive extended regex.

Can sed use extended regex like grep -E?

Yes. Both GNU sed and BSD sed accept the -E flag for extended regular expressions. With it, you can use +, ? and parentheses for groups without escaping them, which makes replacement patterns easier to read.

Does grep -P work on macOS?

The grep that ships with macOS is BSD grep, which doesn't support the -P flag the way GNU grep does. You can install GNU grep with Homebrew, where it's usually available as ggrep. Otherwise, stick with -E and character classes like [0-9].


Leave a Reply