Search Plain and bzip2 Logs with bzgrep Without Losing Exit Statuses
You will search a mixture of ordinary and .bz2 log files with one command, use the alias that matches your pattern, and make a reliable yes-or-no check in a shell script. This guide uses the Debian/Ubuntu bzip2 package version 1.0.8-5.1ubuntu0.1, with GNU grep 3.11 available underneath.
The route
Jump straight to the step you need, or tick off Done means at the end.
Prerequisites: install the bzip2 package and have readable log files. The examples are ordinary user commands and take about five minutes. They read files only; none of them needs sudo or changes a service.
1. Check the installed command
The package provides three names. bzgrep uses grep, bzegrep selects egrep-style regular expressions, and bzfgrep selects fixed-string matching. The wrapper passes its options through to the selected grep program.
command -v bzgrep bzegrep bzfgrep
dpkg-query -W -f='${Package} ${Version}\n' bzip2
Expected output includes three command paths and a line like this:
bzip2 1.0.8-5.1ubuntu0.1
If the first command reports nothing, install bzip2 using your distribution's normal package method. Do not assume that a different installation has the same wrapper details.
2. Search compressed and plain files
Give the pattern first, followed by one or more files. A compressed file is decompressed for the search; an ordinary file is read as it stands. The original files are not rewritten.
bzgrep -n -e 'ERROR|WARN' /var/log/example.log.bz2 /var/log/example.log
-n comes from grep and adds line numbers. -e makes the pattern boundary explicit, which is useful when a pattern begins with a hyphen or when several patterns are involved. Typical output looks like this:
/var/log/example.log.bz2:42:ERROR: disk full
/var/log/example.log:18:WARN: retrying
Replace the paths with files you can read. If you pass more than one file, the wrapper prefixes matching lines with the file name. A missing file or damaged compressed stream produces a diagnostic from the decompressor; treat that as an input problem rather than silently trusting an incomplete result.
3. Choose regular-expression or literal matching
Use bzegrep when the pattern is an extended regular expression. In this example, the vertical bar means "either":
bzegrep -n 'ERROR|WARN' /var/log/example.log.bz2
Use bzfgrep when the text must be taken literally. A string such as ERROR|WARN then searches for those exact characters, including the bar.
bzfgrep -n 'ERROR|WARN' /var/log/example.log.bz2
These names are aliases selected by the program name, not three independent search engines. The same grep options can be passed to each, but the pattern syntax differs.
4. Search compressed data arriving on standard input
With no file argument, bzgrep reads standard input and attempts bzip2 decompression before invoking grep. Feed it the compressed stream directly:
cat /path/to/example.log.bz2 | bzgrep -n -e 'ERROR'
Do not put bzcat in front of bzgrep. That would turn the input into plain text, after which bzgrep still tries to decompress it. If you already decompressed the stream, use ordinary grep instead:
bzcat /path/to/example.log.bz2 | grep -n -e 'ERROR'
Checkpoint: use exactly one decompression step. Choose bzgrep for compressed input and grep for input that is already plain.
5. Use the exit status in a script
Like grep, the wrapper returns zero when it finds a match, one when there is no match, and a non-zero error status for a problem such as an unreadable or invalid input. Test the result immediately so another command cannot replace $?.
if bzgrep -q -e 'ERROR' /var/log/example.log.bz2; then
printf '%s\n' 'An error was found'
else
status=$?
if [ "$status" -eq 1 ]; then
printf '%s\n' 'No error was found'
else
printf 'bzgrep failed with status %s\n' "$status" >&2
exit "$status"
fi
fi
There is no need to decompress a file into a temporary copy for this check. The command reads the source and leaves it unchanged. In a larger pipeline, remember that a pipeline's final status is not automatically the status of every stage in every shell; checking the wrapper directly keeps this example unambiguous.
6. Check the common traps
- A pattern beginning with
-can be mistaken for an option. Supply it with-e, for examplebzgrep -e '-temporary' file.bz2. - Do not use
bzegrepmerely because the file is compressed. The name changes pattern syntax; compression handling comes from the wrapper. - Do not treat exit status one as a broken command. It normally means that no line matched. Handle it separately from higher statuses.
- If
GREPis set,bzgrepuses that program instead ofgrep. Inspect it when results are surprising:printf '%s\n' "${GREP-}". An inherited value such asfgrepchanges matching behaviour.
For a final harmless check, create no files and search a compressed stream:
printf '%s\n' 'ERROR: test' | bzip2 | bzgrep -q -e 'ERROR'
printf 'status=%s\n' "$?"
The expected status is 0. This command compresses the test text in memory through a pipe and does not alter any file.
Done means
bzgrepsearches both plain and bzip2-compressed files without changing them.bzegrepandbzfgrepare used only when their pattern syntax is wanted.- Compressed standard input goes directly to
bzgrep; already decompressed input goes togrep. - Your script distinguishes a match, no match, and an actual input or command failure.