Lecture 9

Regular Expressions
• A regular expression defines a pattern of characters
to be found in a string
• Regular expressions are made up of
– Literal characters to match in the string like “abc”
– Metacharacters are characters that specify how we can
interpret a sequence of literal characters
• Example:
– [abc]+[def]* - find any sequence of one or more of the
letters a, b, c followed by any sequence of zero or more of
the letters d, e, f, for instance abacabdddd or aaaaaab or
adefdef but not ddddeeefff – why not?
• Regular expressions are a powerful tool that a Linux
user can use to search files for particular types of
information
Metacharacters
*, +
• * - match the preceding character 0 or more times
including the empty string
• + - match the preceding character 1 or more times
but not including the empty string
– 0* - any number of 0s (including no 0s)
– 0*1* - any number of 0s followed by any number of 1s
• will match 0001111111, 0111111, 0000000 and the empty
string but not 0000111110, 0000a1111
– 0+1+ - will match 000111111, 0111111, 00000001 but not
0001111110, 0000a11111, 11111 (no 0s)
• We can combine the use of * and + in one
expression
– 0*1+
?, .
• ? matches the preceding character if it occurs exactly
0 or 1 time
– With ?, we limit the number of occurrences
• 0?1? Will match only the empty string, 0, 1 and 01
– 0?1+ will match 1111111, 0111111, 1 but not 001, 0 or the
empty string
• . (period) matches any single character
– b.t will match a ‘b’ followed by anything followed by a ‘t’
such as bat, bet, bit, bot, but, bbt, bct, btt, bzt, b0t, b#t, etc
• We can use the *, + and ? to modify the .
– b.+t will match any string that has a b followed by 1 or
more of any character(s) followed by t as in
• bat, baat, bbt, bcdet, b123456789t but will not match bt
• b.*t will match everything that b.+t matches but will also match bt
[…]
• Match any character that appears in the [ ]
– The list of characters in [ ] can be an enumerated list or a
range
• [aeiou] – enumerated list
• [a-z] – range
• [b-df-hj-np-tv-z] – both enumerated lists and ranges
• *, + and ? can modify the [ ]
– [a-z]+ will match any sequence of 1 or more lower case
letters
– [A-Z][a-z]+ will match any sequence of an upper case
letter followed by 1 or more lower case letters
• To match tif/tiff, use:
– [tT][iI][fF][fF]?
–
but not
[tT][iI][fF]+
[tT][iI][fF][fF]*
[[…]]
• In some cases, the range or list of characters is
already represented using POSIX classes
– POSIX – portable operating system interface – a standard
that has defined among other things these classes
• Each class is denoted using :classname:
–
–
–
–
–
–
:alpha:
:digit:
:alnum: - alphabetic character or digit
:upper:
:lower:
:punct:
:cntrl:
:space: - white space (blank, tab, enter)
:print: - any visible character
• [A-Z][A-Za-z]+ is the same as [[:upper:]][[:alpha:]]+
{n,m}
• Match the preceding character between n and m times
(n & m are integers where n < m)
• {n} – exactly n times
• {n, } – at least n times
• {, m} – no more than m times (including 0)
• { } can modify [ ] and .
– [a-z]{3,4} – 3 or 4 lower case letters
– 0.{5}1 – 0 followed by 5 of any character(s) followed by 1
• A social security number
– [0-9]{3}-[0-9]{2}-[0-9]{4}
• A phone number
– [0-9]{3}-[0-9]{4}
– ([0-9]{3}) [0-9]{3}-[0-9]{4}
\
• Recall in the previous examples we used ( ) for
an area code
– ( ) are reserved for another purpose
– We used . in our regular expression for IP addresses
(but . can match any character)
• \ preceding a metacharacter is used to “escape”
the meaning of the metacharacter
– Without \, . matches any character but \. matches only
the period
– We would have to revise our previous example of an
area code to read \([0-9]{3}\) so that we match the ( )
exactly
[^…]
• The ^ has two uses, here we focus on the use
inside the [ ]
– Inside of [ ], we use ^ to indicate “do not match” or
“match anything except”
– [^a] will match a character that is not “a”
– [^0-9]+ will match anything that is not some
number of digits
• The use of [^…] can be challenging though
– Assume we have the string abCDefg
– Unfortunately, the regex [^A-Z]+ will still match
this string! Why?
Matching Substrings
• A regular expression matches a substring of a string
– It will try to match any substring of the string, not
necessarily the first substring or the entire string
• Consider the regex 0{1,2}[a-zA-Z0-9]+
– This will match the string 0000abcd0000 because the
substring 0abcd appears in the string and the substring
0abcd matches the regex
• actually, the substring 0a matches
• Returning to the previous slide
– abCDefg contains the substring “a” which matches the
expression [^A-Z]+
• at least one character that is not an upper case letter
^ and $
• We will return to the use of [^…] in a bit
• What if we want to match a substring of a string such
that it begins or ends the string?
– The ^ (outside of [ ]) indicates that the regex will only
match a substring of a string if the regex matches at the
beginning of the string
– The $ indicates that the regex will match only at the end
of the string
– Using both ^ and $ means that the regex will only match
the entire string (not substrings)
• For instance, ^[0-9]+$ will match any string that
contains only digits
Examples
• ^[A-Z][a-z]+ [0-9]{1,2}, [12][0-9][0-9]
– Match any string that starts with a date as in March 21,
2004
• [A-Z]{2} [0-9]{5}$
– Match any string that ends with 2 upper case letters, a
space, and 5 digits (the end of an address)
• note this does not ensure that the 2 letter state abbreviation is a
legal state, it could for instance match AB or ZZ
• ^[A-Z][a-z]* [A-Z]\. [A-Z][a-z]+$
– Match any string that consists entirely of a capitalized
word, an initial and a capitalized word (presumably a
person’s full name with middle initial)
• ^$
– Match the empty string
Using [^…]
• To make sure that a string contains no digits
– We could use ^[^0-9]+$
• match anything as long as there is no digit anywhere in the
string
– Without the use of ^ and $ it is hard to control the [^…]
– Notice with the + (^[^0-9]$), we are saying “match a
string that starts with a non-digit and then ends”
• that is, a string of 1 character which is not a digit
– ^[^0-9] – does not start with a digit
– [^A-Z]{2}$ – does not end with a 2 letter abbreviation
– ^[^$]+$ – does not contain a dollar sign
• notice when used in [ ], the metacharacter being evaluated,
$ in this case, does not need to be preceded by \
()
• To apply a metacharacter to a group of characters
(rather than just the preceding character), use the
group in ( )
• Example: match a list of words
– A word will be any lower case letters followed by a space
– A word will be [a-z]+
• A list of words would not be: [a-z]+ +
– The second + would apply to only the space, not the entire
regex
• We will use
– ([a-z]+ )+
• The second + applies to the entire group of characters
([a-z]+ and the space)
| for OR
• We use […] to match any single character in a list
of characters
– What if we want to match any one of a group of
characters?
– Use | to separate each group
• For instance, we want to match any of IN, KY or
OH
– [IKO][NYH] does not do this because it would also
match IY, IH, KN, KH, ON and OY
• Use IN|KY|OH
– Or use (IN|KY|OH) which is more preferred
Examples
• Phone numbers with and without area codes
– \([0-9]{3}\) [0-9]{3}-[0-9]{4} | [0-9]{3}-[0-9]{4}
• note: the blank space around the | should not be there but is
shown here to make the regex readable
• 5 and 9 digit zip codes
– [0-9]{5} | [0-9]{5}-[0-9]{4}
• A name with and without a middle initial
– [A-Z][a-z]* [A-Z]\. [A-Z][a-z]+ | [A-Z][a-z]* [A-Z][a-z]+
• IP address: [0-255].[0-255].[0-255].[0-255]
– What’s wrong with this? How about:
– [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\. [0-9]{1,3}
IP Addresses
[0-9]{1,2} – covers 0-99
Now we need to also cover 100-255
Note that [0-9]{1,2} is not
correct either because we
would not normally use
00 or 09, instead just 0 or 9,
How can we fix this?
Spam Filters
• One common use of regex is to build spam filters to
search not just for keywords, but variations
– Consider we want a regex to spot “viagra” but clever
spammers will try to hide the word by using non-standard
characters or by altering the spelling
• v!agra
• [email protected]
• v_i_a_g_r_a
• We might try any number of regexs to spot this
– [Vv][1Ii!][[email protected]][Gg9][Rr][[email protected]] would catch the first two
but not the third
– [Vv].*[1Ii!].*[[email protected]].*[Gg9].*[Rr].*[[email protected]] would catch all
three
Wildcards in Linux
• Recall from chapter 9 that we use *, ?, [ ] as
wildcards when specifying filenames
– The bash interpreter performs filename expansion by
attempting to match all files in the current directory to
the name listed
– This is a process referred to as globbing
– But we saw that *, ?, and [ ] are also used in regex
– This is confusing!
• We have to differentiate when we use these characters in
such commands as ls, rm, mv, etc from when we use them
in regular expressions
Examples
The contents of our current directory are:
grep
• The most common usage of regex in Linux is
through the program grep
– global regular expression print
• Usage: grep pattern file(s)
– will return every line in the file(s) listed that
contain a substring that matches the pattern
• Very useful for finding content of file(s) that
you are interested in
– e.g., searching all files in a directory that have IP
addresses
Applying grep
• When the IP address pattern is used in grep for all
files in /etc, we get the following (partial) output
Continued
• You might notice that grep matches lines that
contain “mutt-1.4.2.2” thinking this is an IP
address when it is actually a version name
– Our regex was not specific enough although in reality
1.4.2.2 could be an IP address
• We also see the entry “Binary file
/etc/prelink.cache matches” indicate that there
was a match of our pattern to a binary file
– We generally want to ignore binary files, we cannot
view their contents
• The output also tells us the file(s) that matched
– We can add options that eliminate file names or
include the line number(s) that matched
Useful grep Options
More on grep
• grep only uses the standard regular expression set,
which does not include some of the metacharacters
like { } and ( )
• To use the full set of metacharacters, you must use the
extended version of grep, either:
– egrep
– grep –E
• Also, be aware that if you try the IP address search on
/etc as a normal user, you will be given some
permission denied errors since you do not have read
access to all of /etc
Piping to grep/egrep
• Imagine that you want to find all files whose
permissions start with rwx, you could not do
– ls ^rwx
– because ls applies wildcards, not regex
• But you could do this
– ls –l | grep ^rwx
• Similarly, you could pipe ps aux to grep
– ps aux | grep foxr – to find all processes owned by
foxr
– ps aux | 0:00 – find all processes that have used no
CPU time