Like using the word “grok” in conversation, saying “grep” out loud brands you a SuperGeek, at least in the mundane reckoning of members of the “normal” population. They don’t understand that grep is simply an odd concatenation of the phrase “grab regular expression”; and even if they did know, it would mean nothing to them. After all, to them a regular expression is probably something like “What goes around comes around”, “No pain no gain” or the like. But regular expressions are not annoying cliches, they are powerful patterns.
[usr-4@srv-3 usr-4]$ grep "22" /etc/services ssh 22/tcp # SSH Remote Login Protocol ssh 22/udp # SSH Remote Login Protocol imap3 220/tcp # Interactive Mail Access imap3 220/udp # Protocol v3 bpjava-msvc 13722/tcp # BP Java MSVC Protocol bpjava-msvc 13722/udp # BP Java MSVC Protocol wnn6 22273/tcp wnn4 wnn6 22273/ucp wnn4 wnn4_Kr 22305/tcp # used by the kWnn package wnn4_Cn 22289/tcp # used by the cWnn package wnn4_Tw 22321/tcp # used by the tWnn package [usr-4@srv-3 usr-4]$ grep "22/" /etc/services ssh 22/tcp # SSH Remote Login Protocol ssh 22/udp # SSH Remote Login Protocol bpjava-msvc 13722/tcp # BP Java MSVC Protocol bpjava-msvc 13722/udp # BP Java MSVC Protocol [usr-4@srv-3 usr-4]$ grep "\b22/" /etc/services ssh 22/tcp # SSH Remote Login Protocol ssh 22/udp # SSH Remote Login Protocol |
See how the well-crafted regular expression narrows our results? The \b refers to white space at the edge of a word. Here are a few quickies:
Are there empty lines in a file?
[usr-4@srv-3 usr-4]$ grep ^$ /etc/services [usr-4@srv-3 usr-4]$ |
Look for SCSI errors in the syslog:
[root@srv-3 root]# grep -i 'scsi\|error' /var/log/messages Jun 13 03:35:27 srv-3 kernel: st0: Error with sense data: Info fld=0x8000, Current st09:00: sense key Aborted Command Jun 13 03:35:27 srv-3 kernel: Additional sense indicates Scsi parity error |
The “-i” flag means case Insensitive. The pipe, escaped with a backslash, tells grep to look for the string “scsi” or the string “error”.
Look at the root account in the password file:
[usr-4@srv-3 usr-4]$ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [usr-4@srv-3 usr-4]$ grep ^root /etc/passwd root:x:0:0:root:/root:/bin/bash |
Notice how adding the caret (which indicates the beginning of a line) returns only the entry we’re interested in.
Most useful tools have some form of negation, and grep has the “-v” flag, which means reVerse, or, as I like to remember it, grep the Very opposite. This is often useful for filtering out uninteresting log messages like “srv-3 modprobe: modprobe: Can’t locate module sound-slot-1”:
[root@srv-3 usr-4]# grep "Jun 13" /var/log/messages | grep -v sound Jun 13 01:00:00 srv-3 automount[3010]: attempting to mount entry /misc/share Jun 13 01:01:04 srv-3 automount[23407]: expired /misc/share Jun 13 09:17:38 srv-3 kde(pam_unix)[25120]: authentication failure; logname= uid=501 euid=501 tty=:0 ruser= rhost= user=usr-4 Jun 13 11:00:26 srv-3 su(pam_unix)[25534]: session opened for user root by usr-4(uid=501) Jun 13 11:48:48 srv-3 su(pam_unix)[20737]: session closed for user root Jun 13 12:49:23 srv-3 su(pam_unix)[25534]: session closed for user root Jun 13 13:09:55 srv-3 su(pam_unix)[26159]: session opened for user root by usr-4(uid=501) |
This command also illustrates grep’s use in a pipeline, where it is most helpful.
Grep “-l” simply Lists file names with matches, instead of listing the matching lines too. This flag comes in handy in command substitutions. For instance, I may want to edit all of the email lists which contain a certain user name.
[alias@srv-3 alias]$ vi `grep -l usr-4 .qmail*` |
The “-r” flag greps Recursively through a directory structure. I would use this if, for example, I wanted to find all invocations of grep in a directory struture full of old scripts.
[usr-4@srv-3 mis]$ grep -r grep * bb/ext/bb-ldap.sh: set `$PS | $GREP "ldapsearch.*$HOST_IP " | $GREP -v grep` bb/ext/fping.sh: $GREP "^0\.0\.0\.0[ ]" $BBHOME/etc/bb-hosts | $GREP -v noconn | grep noping > $BBTMP/fping.$$ bb/ext/jrun.sh:set `ps auxwww | grep JRun | grep default | head -1`;shift;shift; shift;shift;shift;echo $1 > /tmp/OUTPUT.$$ bb/ext/popchart.sh:popstatus=$(grep "closed" $TMPFILE) bb/ext/swraid.sh:TEST0=`egrep ^md0 /proc/mdstat` scripts/prefilter.sh:grep -v "\.jpg" $TEMP/${FATFILE}.2 > $TEMP/${FATFILE} shutall/shutall.sh: up=`ping $machine -c 1 | grep "64 bytes from" | cut -f4 -d" "` |
Grep can return lines of context in addition to the matching lines. For instance:
[root@srv-3 usr-4]# dmesg | grep -A 8 3c59x 3c59x: Donald Becker and others. www.scyld.com/network/vortex.html See Documentation/networking/vortex.txt 00:0d.0: 3Com PCI 3c905B Cyclone 100baseTx at 0xb800. Vers LK1.1.18-ac 00:50:04:7b:e2:de, IRQ 11 product code 5447 rev 00.9 date 03-22-99 Internal config register is 1800000, transceivers 0xa. 8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface. MII transceiver found at address 24, status 782d. Enabling bus-master transmits and whole-frame receives. |
After matching the string “3c59x”, the “-A” flag grabs n lines of context After the matching line. There is a corresponding “-B” flag which grabs n lines of context Before the match. This can be very useful for grabbing event sequences out of system log files, parsing machine-generated alert emails, and anything where the data has a more-or-less fixed length which can be identified at the beginning or end by a pattern. You’ll know it when you have a use for this one.
Don’t forget that grep and find are two great tastes that taste great together.
[usr-4@srv-3 usr-4]$ find . -name *.sh -exec grep -i "grep" {} \; |
And now, SuperGeek, with your powerful regular expressions, you grok what grep is all about.