Anda di halaman 1dari 18

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

1 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Home
Books
Projects
Sitemap
Feedback
About Me
Advertise

The road to wisdom? Well its plain and simple to express: Err and err and err again, but less and less and less.
Piet Hein

I am doing a startup!

Cross-browser testing from your browser!


I have written my fourth book!

Be faster than Larry Wall at command line!


Follow me on Twitter for my latest adventures!
Awk Programming 49 Comments October 23, 2008

10 Awk Tips, Tricks and Pitfalls


Hi guys and girls, this is the first guest post on my blog. It's written by Waldner from #awk on FreeNode IRC
Network. He works as a sysadmin and does shell scripting as a hobby. Waldner will be happy to take any
questions about the article. You can ask them in the comments of this post or on IRC.
This article takes a look at ten tips, tricks and pitfalls in Awk programming language. They are mostly taken
from the discussions in #awk IRC channel. Here they are:
1. Be idiomatic!
2. Pitfall: shorten pipelines
3. Print lines using ranges
4. Split file on patterns
5. Locale-based pitfalls
6. Parse CSV
7. Pitfall: validate an IPv4 address
8. Check whether two files contain the same data
9. Pitfall: contexts and variable types in awk
10. Pulling out things

Be idiomatic!
Update: Mr. Waldner just notified me that he has improved the tips on being idiomatic. See "Idiomatic Awk" on his website!
In this paragraph, we give some hints on how to write more idiomatic (and usually shorter and more efficient) awk programs. Many awk programs you're likely to encounter, especially short
ones, make large use of these notions.
Suppose one wants to print all the lines in a file that match some pattern (a kind of awk-grep, if you like). A reasonable first shot is usually something like
awk '{if ($0 ~ /pattern/) print $0}'

That works, but there are a number of things to note.


The first thing to note is that it is not structured according to the awk's definition of a program, which is
condition { actions }

Our program can clearly be rewritten using this form, since both the condition and the action are very clear here:
awk '$0 ~ /pattern/ {print $0}'

Our next step in the perfect awk-ification of this program is to note that /pattern/ is the same as $0 ~ /pattern/. That is, when awk sees a single regular expression used as an expression, it
implicitly applies it to $0, and returns success if there is a match. Then we have:
awk '/pattern/ {print $0}'

Now, let's turn our attention to the action part (what's inside braces). print $0 is a redundant statement, since print alone, by default, prints $0.

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

2 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

awk '/pattern/ {print}'

But now we note that, when it finds that a condition is true, and there are no associated actions, awk performs a default action that is (you guessed it) print (which we already know is
equivalent to print $0). Thus we can do this:
awk '/pattern/'

Now we have reduced the initial program to its simplest (and more idiomatic) form. In many cases, if all you want to do is print some lines, according to a condition, you can write awk
programs composed only of a condition (although complex):
awk '(NR%2 && /pattern/) || (!(NR%2) && /anotherpattern/)'

That prints odd lines that match /pattern/, or even lines that match /anotherpattern/. Naturally, if you don't want to print $0 but instead do something else, then you'll have to manually add a
specific action to do what you want.
From the above, it follows that
awk 1
awk '"a"'

# single quotes are important!

are both awk programs that just print their input unchanged. Sometimes, you want to operate only on some lines of the input (according to some condition), but also want to print all the lines,
regardless of whether they were affected by your operation or not. A typical example is a program like this:
awk '{sub(/pattern/,"foobar")}1'

This tries to replace "pattern" with "foobar". Whether or not the substitution succeeds, the always-true condition "1" prints each line (you could even use "42", or "19", or any other nonzero
value if you want; "1" is just what people traditionally use). This results in a program that does the same job as sed 's/pattern/foobar/'. Here are some examples of typical awk idioms, using
only conditions:
awk
awk
awk
awk
awk
awk
awk
awk
awk
awk
awk

'NR % 6'
'NR > 5'
'$2 == "foo"'
'NF >= 6'
'/foo/ && /bar/'
'/foo/ && !/bar/'
'/foo/ || /bar/'
'/foo/,/bar/'
'NF'
'NF--'
'$0 = NR" "$0'

#
#
#
#
#
#
#
#
#
#
#

prints all lines except those divisible by 6


prints from line 6 onwards (like tail -n +6, or sed '1,5d')
prints lines where the second field is "foo"
prints lines with 6 or more fields
prints lines that match /foo/ and /bar/, in any order
prints lines that match /foo/ but not /bar/
prints lines that match /foo/ or /bar/ (like grep -e 'foo' -e 'bar')
prints from line matching /foo/ to line matching /bar/, inclusive
prints only nonempty lines (or: removes empty lines, where NF==0)
removes last field and prints the line
prepends line numbers (assignments are valid in conditions)

Another construct that is often used in awk is as follows:


awk 'NR==FNR { # some actions; next} # other condition {# other actions}' file1 file2

This is used when processing two files. When processing more than one file, awk reads each file sequentially, one after another, in the order they are specified on the command line. The
special variable NR stores the total number of input records read so far, regardless of how many files have been read. The value of NR starts at 1 and always increases until the program
terminates. Another variable, FNR, stores the number of records read from the current file being processed. The value of FNR starts from 1, increases until the end of the current file, starts
again from 1 as soon as the first line of the next file is read, and so on. So, the condition "NR==FNR" is only true while awk is reading the first file. Thus, in the program above, the actions
indicated by "# some actions" are executed when awk is reading the first file; the actions indicated by "# other actions" are executed when awk is reading the second file, if the condition in
"# other condition" is met. The "next" at the end of the first action block is needed to prevent the condition in "# other condition" from being evaluated, and the actions in "# other actions"
from being executed while awk is reading the first file.
There are really many problems that involve two files that can be solved using this technique. Here are some examples:
# prints lines that are both in file1 and file2 (intersection)
awk 'NR==FNR{a[$0];next} $0 in a' file1 file2

Here we see another typical idiom: a[$0] has the only purpose of creating the array element indexed by $0. During the pass over the first file, all the lines seen are remembered as indexes of
the array a. The pass over the second file just has to check whether each line being read exists as an index in the array a (that's what the condition $0 in a does). If the condition is true, the line
is printed (as we already know).
Another example. Suppose we have a data file like this
20081010 1123 xxx
20081011 1234 def
20081012 0933 xyz
20081013 0512 abc
20081013 0717 def
...thousand of lines...

where "xxx", "def", etc. are operation codes. We want to replace each operation code with its description. We have another file that maps operation codes to human readable descriptions, like
this:
abc withdrawal
def payment
xyz deposit
xxx balance
...other codes...

We can easily replace the opcodes in the data file with this simple awk program, that again uses the two-files idiom:
# use information from a map file to modify a data file
awk 'NR==FNR{a[$1]=$2;next} {$3=a[$3]}1' mapfile datafile

First, the array a, indexed by opcode, is populated with the human readable descriptions. Then, it is used during the reading of the second file to do the replacements. Each line of the datafile
is then printed after the substitution has been made.
Another case where the two-files idiom is useful is when you have to read the same file twice, the first time to get some information that can be correctly defined only by reading the whole
file, and the second time to process the file using that information. For example, you want to replace each number in a list of numbers with its difference from the largest number in the list:
# replace each number with its difference from the maximum
awk 'NR==FNR{if($0>max) max=$0;next} {$0=max-$0}1' file file

Note that we specify "file file" on the command line, so the file will be read twice.

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

3 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Caveat: all the programs that use the two-files idiom will not work correctly if the first file is empty (in that case, awk will execute the actions associated to NR==FNR while reading the
second file). To correct that, you can reinforce the NR==FNR condition by adding a test that checks that also FILENAME equals ARGV[1].

Pitfall: shorten pipelines


It's not uncommon to see lines in scripts that look like this:
somecommand | head -n +1 | grep foo | sed 's/foo/bar/' | tr '[a-z]' '[A-Z]' | cut -d ' ' -f 2

This is just an example. In many cases, you can use awk to replace parts of the pipeline, or even all of it:
somecommand | awk 'NR>1 && /foo/{sub(/foo/,"bar"); print toupper($2)}'

It would be nice to collect here many examples of pipelines that could be partially or completely eliminated using awk.

Print lines using ranges


Yes, we all know that awk has builtin support for range expressions, like
# prints lines from /beginpat/ to /endpat/, inclusive
awk '/beginpat/,/endpat/'

Sometimes however, we need a bit more flexibility. We might want to print lines between two patterns, but excluding the patterns themselves. Or only including one. A way is to use these:
# prints lines from /beginpat/ to /endpat/, not inclusive
awk '/beginpat/,/endpat/{if (!/beginpat/&&!/endpat/)print}'
# prints lines from /beginpat/ to /endpat/, not including /beginpat/
awk '/beginpat/,/endpat/{if (!/beginpat/)print}'

It's easy to see that there must be a better way to do that, and in fact there is. We can use a flag to keep track of whether we are currently inside the interesting range or not, and print lines
based on the value of the flag. Let's see how it's done:
# prints lines from /beginpat/ to /endpat/, not inclusive
awk '/endpat/{p=0};p;/beginpat/{p=1}'
# prints lines from /beginpat/ to /endpat/, excluding /endpat/
awk '/endpat/{p=0} /beginpat/{p=1} p'
# prints lines from /beginpat/ to /endpat/, excluding /beginpat/
awk 'p; /endpat/{p=0} /beginpat/{p=1}'

All these programs just set p to 1 when /beginpat/ is seen, and set p to 0 when /endpat/ is seen. The crucial difference between them is where the bare "p" (the condition that triggers the
printing of lines) is located. Depending on its position (at the beginning, in the middle, or at the end), different parts of the desired range are printed. To print the complete range (inclusive),
you can just use the regular /beginpat/,/endpat/ expression or use the flag technique, but reversing the order of the conditions and associated patterns:
# prints lines from /beginpat/ to /endpat/, inclusive
awk '/beginpat/{p=1};p;/endpat/{p=0}'

It goes without saying that while we are only printing lines here, the important thing is that we have a way of selecting lines within a range, so you can of course do anything you want instead
of printing.

Split file on patterns


Suppose we have a file like this
line1
line2
line3
line4
FOO1
line5
line6
FOO2
line7
line8
FOO3
line9
line10
line11
FOO4
line12
FOO5
line13

We want to split this file on all the occurrences of lines that match /^FOO/, and create a series of files called, for example, out1, out2, etc. File out1 will contain the first 4 lines, out2 will
contain "line5" and "line6", etc. There are at least two ways to do that with awk:
# first way, works with all versions of awk
awk -v n=1 '/^FOO[0-9]*/{close("out"n);n++;next} {print > "out"n}' file

Since we don't want to print anything when we see /^FOO/, but only update some administrative data, we use the "next" statement to tell awk to immediately start processing the next record.
Lines that do not match /^FOO/ will instead be processed by the second block of code. Note that this method will not create empty files if an empty section is found (eg, if "FOO5\nFOO6" is
found, the file "out5" will not be created). The "-v n=1" is used to tell awk that the variable "n" should be initialized with a value of 1, so effectively the first output file will be called "out1".
Another way (which however needs GNU awk to work) is to read one chunk of data at a time, and write that to its corresponding out file.
# another way, needs GNU awk
LC_ALL=C gawk -v RS='FOO[0-9]*\n' -v ORS= '{print > "out"NR}' file

The above code relies on the fact that GNU awk supports assigning a regular expression to RS (the standard only allows a single literal character or an empty RS). That way, awk reads a
series of "records", separated by the regular expression matching /FOO[0-9]*\n/ (that is, the whole FOO... line). Since newlines are preserved in each section, we set ORS to empty since we
don't want awk to add another newline at the end of a block. This method does create an empty file if an empty section is encountered. On the downside, it's a bit fragile because it will
produce incorrect results if the regex used as RS appears somewhere else in the rest of the input.

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

4 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

We will see other examples where gawk's support for regexes as RS is useful. Note that the last program used LC_ALL=C at the beginning...

Locale-based pitfalls
Sometimes awk can behave in an unexpected way if the locale is not C (or POSIX, which should be the same). See for example this input:
-rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--

1
1
1
1
1
1
1
1

waldner
waldner
waldner
waldner
waldner
waldner
waldner
waldner

users
users
users
users
users
users
users
users

46592
11509
11193
19073
36332
33395
54272
20573

2003-09-12
2008-10-07
2008-10-07
2008-10-07
2008-10-07
2008-10-07
2008-09-18
2008-10-07

09:41
17:42
17:41
17:45
17:03
16:53
16:20
17:50

file1
file2
file3
file4
file5
file6
file7
file8

You'll recognize the familiar output of ls -l here. Let's use a non-C locale, say, en_US.utf8, and try an apparently innocuous operation like removing the first 3 fields.
$ LC_ALL=en_US.utf8 awk --re-interval '{sub(/^([^[:space:]]+[[:space:]]+){3}/,"")}1' file
-rw-r--r-- 1 waldner users 46592 2003-09-12 09:41 file1
-rw-r--r-- 1 waldner users 11509 2008-10-07 17:42 file2
-rw-r--r-- 1 waldner users 11193 2008-10-07 17:41 file3
-rw-r--r-- 1 waldner users 19073 2008-10-07 17:45 file4
-rw-r--r-- 1 waldner users 36332 2008-10-07 17:03 file5
-rw-r--r-- 1 waldner users 33395 2008-10-07 16:53 file6
-rw-r--r-- 1 waldner users 54272 2008-09-18 16:20 file7
-rw-r--r-- 1 waldner users 20573 2008-10-07 17:50 file8

It looks like sub() did nothing. Now change that to use the C locale:
$ LC_ALL=C awk --re-interval
users 46592 2003-09-12 09:41
users 11509 2008-10-07 17:42
users 11193 2008-10-07 17:41
users 19073 2008-10-07 17:45
users 36332 2008-10-07 17:03
users 33395 2008-10-07 16:53
users 54272 2008-09-18 16:20
users 20573 2008-10-07 17:50

'{sub(/^([^[:space:]]+[[:space:]]+){3}/,"")}1' file
file1
file2
file3
file4
file5
file6
file7
file8

Now it works. Another localization issue is the behavior of bracket expressions matching, like for example [a-z]:
$ echo '' | LC_ALL=en_US.utf8 awk '/[a-z]/'

This may or may not be what you want. When in doubt or when facing an apparently inexplicable result, try putting LC_ALL=C before your awk invocation.

Parse CSV
Update: Mr. Waldner just notified me that he has improved this section of the article on his website. See "CVS Parsing With Awk".
This is another thing people do all the time with awk. Simple CSV files (with fields separated by commas, and commas cannot appear anywhere else) are easily parsed using FS=','. There can
be spaces around fields, and we don't want them, like eg
field1

field2

, field3

, field4

Exploiting the fact that FS can be a regex, we could try something like FS='^ *| *, *| *$'. This can be problematic for two reasons:
actual data field might end up correponding either to awk's fields 1 ... NF or 2 ... NF, depending on whether the line has leading spaces or not;
for some reason, assigning that regex to FS produces unexpected results if fields have embedded spaces (anybody knows why?).
In this case, it's probably better to parse using FS=',' and remove leading and trailing spaces from each field:
# FS=','
for(i=1;i<=NF;i++){
gsub(/^ *| *$/,"",$i);
print "Field " i " is " $i;
}

Another common CSV format is


"field1","field2","field3","field4"

Assuming double quotes cannot occur in fields. This is easily parsed using FS='^"|","|"$' (or FS='","|"' if you like), keeping in mind that the actual fields will be in position 2, 3 ... NF-1.
We can extend that FS to allow for spaces around fields, like eg
"field1"

, "field2",

"field3" , "field4"

by using FS='^ *"|" *, *"|" *$'. Usable fields will still be in positions 2 ... NF-1. Unlike the previous case, here that FS regex seems to work fine. You can of course also use FS=',', and
remove extra characters by hand:
# FS=','
for(i=1;i<=NF;i++){
gsub(/^ *"|" *$/,"",$i);
print "Field " i " is " $i;
}

Another CSV format is similar to the first CSV format above, but allows for field to contain commas, provided that the field is quoted:
field1, "field2,with,commas"

field3

"field4,foo"

We have a mixture of quoted and unquoted fields here, which cannot parsed directly by any value of FS (that I know of, at least). However, we can still get the fields using match() in a loop
(and cheating a bit):
$0=$0",";
while($0) {
match($0,/[^,]*,| *"[^"]*" *,/);
sf=f=substr($0,RSTART,RLENGTH);
gsub(/^ *"?|"? *,$/,"",f);

# yes, cheating

# save what matched in sf


# remove extra stuff

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

5 of 18

print "Field " ++c " is " f;


sub(sf,"");

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

# "consume" what matched

As the complexity of the format increases (for example when escaped quotes are allowed in fields), awk solutions become more fragile. Although I should not say this here, for anything more
complex than the last example, I suggest using other tools (eg, Perl just to name one). Btw, it looks like there is an awk CSV parsing library here: http://lorance.freeshell.org/csv/ (I have not
tried it).

Pitfall: validate an IPv4 address


Let's say we want to check whether a given string is a valid IPv4 address (for simplicity, we limit our discussion to IPv4 addresses in the traditiona dotted quad format here). We start with this
seemingly valid program:
awk -F '[.]' 'function ok(n){return (n>=0 && n<=255)} {exit (ok($1) && ok($2) && ok($3) && ok($4))}'

This seems to work, until we pass it '123b.44.22c.3', which it happily accepts as valid. The fact is that, due to the way awk's number to string conversion works, some strings may "look like"
numbers to awk, even if we know they are not. The correct thing to do here is to perform a string comparison against a regular expression:
awk -F '[.]' 'function ok(n) {
return (n ~ /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/)
}
{exit (ok($1) && ok($2) && ok($3) && ok($4))}'

Check whether two files contain the same data


We want to check whether two (unsorted) files contain the same data, that is, the set of lines of the first file is the same set of lines of the second file. One way is of course sorting the two files
and processing them with some other tool (for example, uniq or diff). But we want to avoid the relatively expensive sort operation. Can awk help us here? The answer (you guessed it) is yes.
If we know that the two files do not contain duplicates, we can do this:
awk '!($0 in a) {c++;a[$0]} END {exit(c==NR/2?0:1)}' file1 file2

and check the return status of the command (0 if the files are equal, 1 otherwise). The assumption we made that the two files must not contain duplicate lines is crucial for the program to work
correctly. In essence, what it does is to keep track of the number of different lines seen. If this number is exactly equal to half the number of total input records seen, then the two files must be
equal (in the sense described above). To understand that, just realize that, in all other cases (ie, when a file is only a partial subset or is not a subset of the other), the total number of distinct
lines seen will always be greater than NR/2.
The program's complexity is linear in the number of input records.

Pitfall: contexts and variable types in awk


We have this file:
1,2,3,,5,foo
1,2,3,0,5,bar
1,2,3,4,5,baz

and we want to replace the last field with "X" only when the fourth field is not empty. We thus do this:
awk -F ',' -v OFS=',' '{if ($4) $6="X"}1'

But we see that the substitution only happens in the last line, instead of the last two as we expected. Why?
Basically, there are only two data types in awk: strings and numbers. Internally, awk does not assign a fixed type to the variables; they are literally considered to be of type "number" and
"string" at the same time, with the number 0 and the null string being equivalent. Only when a variable is used in the program, awk automatically converts it to the type it deems appropriate
for the context. Some contexts strictly require a specific type; in that case, awk automatically converts the variable to that type and uses it. In contexts that does not require a specific type, awk
treats variables that "look like" numbers as numbers, and the other variables are treated as strings. In out example above, the simple test "if ($4)" does not provide a specific context, since the
tested variable can be anything. In the first line, $4 is an empty string, so awk considers it false for the purposes of the test. In the second line, $4 is "0". Since it look like a number, awk uses it
like a number, ie zero. Since 0 is considered false, the test is unsuccessful and the substitution is not performed.
Luckily, there is a way to help awk and tell it exactly what we want. We can use string concatenation and append an empty string to the variable (which does not change its value) to explicitly
tell awk that we want it to treat it like a string, or, conversely, add 0 to the variable (again, without changing its value) to explicitly tell awk that we want a number. So this is how our program
should be to work correctly:
awk -F ',' -v OFS=',' '{if ($4"") $6="X"}1'

# the "" forces awk to evaluate the variable as a string

With this change, in the second line the if sees the string "0", which is not considered false, and the test succeeds, just as we wanted.
As said above, the reverse is also true. Another typical problematic program is this:
awk '/foo/{tot++} END{print tot}'

This, in the author's intention, should count the number of lines that match /foo/. But if /foo/ does not appear in the input, the variable tot retains its default initial value (awk initializes all
variables with the dual value "" and 0). print expects a string argument, so awk supplies the value "". The result is that the program prints just an empty line. But we can force awk to treat the
variable as numeric, by doing this:
awk '/foo/{tot++} END{print tot+0}'

The seemingly innocuous +0 has the effect of providing numeric context to the variable "tot", so awk knows it has to prefer the value 0 of the variable over the other possible internal value
(the empty string). Then, numeric-to-string conversion still happens to satisfy print, but this time what awk converts to string is 0, so print sees the string "0" as argument, and prints it.
Note that, if an explicit context has been provided to a variable, awk remembers that. That can lead to unexpected results:
# input: 2.5943 10
awk '{$1=sprintf("%d",$1);
# truncates decimals, but also explicitly turns $1 into a string!
if($1 > $2) print "something went wrong!" }
# this is printed

Here, after the sprintf(), awk notes that we want $1 to be a string (in this case, "2"). Then, when we do if($1>$2), awk sees that $2 has no preferred type, while $1 does, so it converts $2 into
a string (to match the wanted type of $1) and does a string comparison. Of course, 99.9999% of the times this is not what we want here. In this case, the problem is easily solved by doing "if
($1+0 > $2)" (doing $2+0 instead WON'T work!), doing "$1=$1+0" after the sprintf(), or using some other means to truncate the value of $1, that does not give it explicit string type.

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

6 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Pulling out things


Suppose you have a file like this:
Yesterday I was walking in =the street=, when I saw =a
black dog=. There was also =a cat= hidden around there. =The sun= was shining, and =the sky= was blue.
I entered =the
music
shop= and I bought two CDs. Then I went to =the cinema= and watched =a very nice movie=.
End of the story.

Ok, silly example, fair enough. But suppose that we want to print only and all the parts of that file that are like =something=. We have no knowledge of the structure of the file. The parts
we're interested in might be anywere; they may span lines, or there can be many of them on a single line. This seemingly daunting and difficult task is actually easily accomplished with this
small awk program:
awk -v RS='=' '!(NR%2)'
# awk -v RS='=' '!(NR%2){gsub(/\n/," ");print}'

# if you want to reformat embedded newlines

Easy, wasn't it? Let's see how this works. Setting RS to '=' tells awk that records are separated by '=' (instead of the default newline character). If we look at the file as a series of records
separated by '=', it becomes clear that what we want are the even-numbered records. So, just throw in a condition that is true for even-numbered records to trigger the printing.
GNU awk can take this technique a step further, since it allows us to assign full regexes to RS, and introduces a companion variable (RT) that stores the part of the input that actually matched
the regex in RS. This allows us, for example, to apply the previous technique when the interesting parts of the input are delimited by different characters or string, like for example when we
want everything that matches <tag>something</tag>. With GNU awk, we can do this:
gawk -v RS='</?tag>' 'RT=="</tag>"'

or again
gawk -v RS='</?tag>' '!(NR%2)'

and be done with that. Another nice thing that can be done with GNU awk and RT is printing all the parts of a file that match an arbitrary regular expression (something otherwise usually not
easily accomplished). Suppose that we want to print everything that looks like a number in a file (simplifiying, here any sequence of digits is considered a number, but of course this can be
refined), we can do just this:
gawk -v RS='[0-9]+' 'RT{print RT}'

Checking that RT is not null is necessary because for the last record of a file RT is null, and an empty line would be printed in that case. The output produced by the previous program is
similar to what can be obtained using grep -o. But awk can do better than that. We can use a slight variation of this same technique if we want to add context to our search (something grep -o
alone cannot do). For example, let's say that we want to print all numbers, but only if they appear inside "--", eg like --1234--, and not otherwise. With gawk, we can do this:
gawk -v RS='--[0-9]+--' 'RT{gsub(/--/,"",RT);print RT}'

So, a carefully crafted RS selects only the "right" data, that can be subsequently extracted safely and printed.
With non-GNU awk, matching all occurrences of an expression can still be done, it just requires more code. See FindAllMatches.

Have fun!
Have fun learning Awk! It's a fun language to know.
Ps. I will go silent for a week. I have an on-site interview with Google in Mountain View, California. I'll be back on 31st of October and will post something new in the first week of
November!
Tweet

29

Like

Tags: awk, csv, file, idioms, ip address, ipv4, tips, tricks, waldner
49 Comments 392,403 Views Short URL

Related Posts
Awk, Nawk and GNU Awk Cheat Sheet
Update on Famous Awk One-Liners Explained: String and Array Creation
Plain Text Versions of Sed, ed and AWK Cheat Sheets
Revisiting GNU Awk YouTube Video Downloader
Famous Awk One-Liners Explained, Part III: Selective Printing and Deleting of Certain Lines
Golfing the Extraction of IP Addresses from ifconfig
Traffic Accounting with Linux IPTables
Solving Google Treasure Hunt Puzzle 4: Prime Numbers
Annoying key combination that you should unmap in Linux
Downloading YouTube Videos with GNU Awk

Comments

Unix User Permalink


October 24, 2008, 00:20
Something I often need to do is match lines against a regexp, and print out a matching group within that line. But I have never been able to find a way to do this in awk, and end up resorting to
Perl.
So - is there a way to do something like this?
/abc([0-9]+)def/ { print group(1); }
so that input of:

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

7 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

abc654def
produces:
654
Thanks!
Reply to this comment

frank_wu Permalink
September 19, 2011, 07:32
you can install gawk,and do like this:
Syntax
gawk 'mathc($0,regex,array){print array[1]}' file
example:
gawk 'match($0, "https?:\/\/(.*?google.*?)/", array) {print array[1]}' filename
Reply to this comment

waldner Permalink
October 24, 2008, 08:57
Unix User:
That is easily done with gawk, see the last tip. You could do eg
gawk -v RS='abc([0-9]+)def' 'RT{gsub(/[^0-9]/,"",RT)print RT}

Of course, the exact regexes used for RS and in the gsub vary from time to time depending on what you want to achieve. Another solution is using gensub(), again from gawk.
Unfortunately, standard awk regexes lack backreferences, so getting what you want using standard awk would not be easy.
Reply to this comment

jamesp@yahoo.com Permalink
October 09, 2014, 16:01
but less wordy in perl :
perl -le 'shift =~ /(\d+)/;print $1' abc123def
Reply to this comment

jamesp@yahoo.com Permalink
October 09, 2014, 16:04
or even
perl -le 'print shift =~ /(\d+)/' abc123def
Reply to this comment

waldner Permalink
October 24, 2008, 11:39
To pkrumins: something got lost during reformatting. The first two examples that uses GNU awk and RT should be as follows:
"...like for example when we want everything that matches something. With GNU awk, we can do this:
gawk -v RS='' 'RT==""'
or again
gawk -v RS='' '!(NR%2)'

Reply to this comment

waldner Permalink
October 24, 2008, 11:40
ok, now I see :-)
Let's see it this time it works:
"...like for example when we want everything that matches <tag>something</tag>. With GNU awk, we can do this:
gawk -v RS='</?tag>' 'RT=="</tag>"'
or again
gawk -v RS='</?tag>' '!(NR%2)'

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

8 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Reply to this comment

waldner Permalink
October 24, 2008, 15:29
pkrumins:
no, using int(n)==n to check if a number is valid in an IPv4 address won't work. It will accept, for example, "+100" which is not valid in a dotted quad IPv4 address.
Reply to this comment

Thorsten Strusch Permalink


October 24, 2008, 23:43
@Unix User:
tr should be the tool of your choice:
echo "abc654dEF" | tr -d 'a-zA-Z'
654

Reply to this comment

zts Permalink
October 25, 2008, 02:22
Alternate solution for the IP address validation function:
function ok(n){ return (n !~ /[^0-9]/) && (n>=0 && nThis just adds an additional test to assert that the value being tested contains only numeric characters.

Reply to this comment

zts Permalink
October 25, 2008, 02:25
(I'll try that again) Alternate solution for the IP address validation function - same as your first suggestion, but with a condition allowing only numeric values:
function ok(n){ return (n !~ /[^0-9]/) && (n>=0 && n

Reply to this comment

Ruslan Abuzant Permalink


October 25, 2008, 14:01
Keep us updated with what goes there at Mt. View, CA :D
Good luck newbie googler (Y)
Reply to this comment

PS Permalink
October 25, 2008, 19:58
Found this site due to the article you wrote on perl one-liner youtube downloader (which no longer works) and I see you've digressed. Why would anyone go from perl to awk? Did you hit
your head?
Reply to this comment

waldner Permalink
October 27, 2008, 18:27
@zts:
That's a good one! Thank you.
@PS:
I agree perl is more powerful of awk. But I think you'll agree that that is not a valid reason to stop using awk (or sed, or cat, or all the other tools that perl could easily replace).
Reply to this comment

Steve Kinoshita Permalink


October 29, 2008, 03:13
Hi!
This is a really helpful article thanks!
I am trying to remove all double quotes and angled brackets, and replcase all semicolons and colons with newlines in a text file with gawk.
Can you help?

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

9 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

I have trouble making my scripts work.


I use gawk3.1.6 for Windows and following are some of the codes I have tried.
awk {gsub(/,/,"\n")}1
awk {gsub(/\"/,"")}1

Reply to this comment

waldner Permalink
October 29, 2008, 14:28
@Steve Kinoshita:
To remove all double quotes and angled brackets, try this:
gsub(/["<>]/,"")

To replace all semicolons and colons with newlines, try this:


gsub(/[;:]/,"\n")

Since you say you're using windows, I suggest you put your awk program in a separate file, and then run it using
awk -f prog.awk yourfile

Reply to this comment

Marco R. Permalink
November 03, 2008, 01:22
In "Pitfall: validate an IPv4 address" awk returns not-zero when the input is a valid IPv4 address and zero otherwise. That's because awk's boolean arithmetic assigns 1 to True and 0 to False.
This is not what a shell programmer would expect because shells usually act in the opposite way: true=0 and false=1.
Thus, the final "shell-compatible" script should be:
awk -F '[.]' 'function ok(n) {
return (n ~ /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/)
}
{exit (! ( ok($1) && ok($2) && ok($3) && ok($4) ) )}'

However, I'd prefer to use something simpler:


function ok(n) {if (n ~ /[^[:digit:]]/)

return 1==0;return (nNot fully tested but should work the samemy 2 pennies ;)

Reply to this comment

waldner Permalink
November 03, 2008, 11:55
@Marco R:
Awk's logic is not broken. I just follows the C (and many other languages) model, where any nonzero value is considered true, so you can do
"if <something> then ...".
The shell uses the same logic, but it just uses zero to indicate success and nonzero to indicate failure, but that's not necessarily a bad thing.
In the particular application of validating an address, the return value depends on the context you'll use that. If the function ok() is to be invoked within the awk program only, then I think
returning 1 for success makes sense (and perhaps return 0 at the end of the overall awk program if it succeeded in its entirety). If, on the other hand, you want to use the awk program directly
from the shell, only to check IP addresses, then you can return 0 for success, as you suggest. I think it's a matter of personal taste after all.
Regarding the function ok() you suggest, something similar was proposed by another reader (see previous comments). However, I don't see the point in returning "1==0" instead of simply 0.
Thanks for your comment!
Reply to this comment

karl Permalink
November 07, 2008, 09:21
It's easy with sed:
echo abc654def | sed -E -n -e 's/abc([0-9]+)def/\1/p'
Reply to this comment

Rob Permalink
November 10, 2008, 18:32
Hi
Thank you for the tips.
Could I ask something basic? If I have an IP=123.123.123.123 how do I use the 'Pitfall: validate an IPv4 address' to validate the variable/input?
Thanks

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

10 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Rob
Reply to this comment

waldner Permalink
November 10, 2008, 22:41
@Rob:
many solutions have been proposed in the article and in the comments. To summarize, you can build a function that accepts an argument and checks if that argument is a number and is
between 0 and 255, and use that function to check that all four octets are valid. The skeleton of a program is as follows:
awk -F[.] '
function ok(n) {
# do something here to check the value of n,
# and return 1 if it's valid, 0 otherwise
}
{exit ( ok($1) && ok($2) && ok($3) && ok($4) )'

(to make it more robust, you may optionally check that the number of input fields (ie, octets) is exactly 4, no more and no less)
so you will call it as follows, for example:
echo "123.123.123.123" | awk -F[.] '...'
if [ $? -eq 1 ]; then
echo "valid IP address"
else
echo "invalid IP address"
fi

where the part '...' is the complete awk program.


Note that, to follow shell conventions, you may choose to have the awk program return 0 on success and 1 on failure instead.
That said, here are two ways to implement function ok:
function ok(n) {
# string check using a regex
return (n~/^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/)
}
function ok(n) {
# check that n is a number, and then that
# it is in the range 0-255
return (n~/^[0-9]*$/ && n>=0 && n<=255)
}

Again, you might choose to negate the return values if you want to return 0 on success.
Reply to this comment

HS Permalink
November 17, 2008, 08:18
Really great way to explain things and reading it makes me humble too
Thank you guys !
Reply to this comment

joe Permalink
December 11, 2008, 23:12
I read the article but can not figure out how to get awk to print the lines of a file, minus the duplicates. For example I have a file with a bunch of IP addresses some of which are duplicated
throughout the file. I am only interested in having the output display unique IP addresses. any ideas?
Reply to this comment

Peteris Krumins pkrumins Permalink


December 11, 2008, 23:23
joe, it's really simple (you won't believe it):
awk '!a[$0]++'

Reply to this comment

krishna Permalink
May 11, 2010, 04:14
yes it works like a magic,, It appears to have to same effect as $>cat
<file>
| uniq
How does awk work here,, can someone explain?
Reply to this comment

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

11 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Ed Permalink
February 19, 2009, 01:02
How can I search a file for a pattern ($3 in input line) and for a match print $1 and $2 and $3, but for no match print "na " "na " $3?
Reply to this comment

Peteris Krumins pkrumins Permalink


February 19, 2009, 09:34
Ed, easy:
$ awk '$3 ~ /pattern/ { print $1, $2, $3 } $3 !~ { print "na", "na", $3 }'

or
$ awk '$3 ~ /pattern/ { print $1, $2, $3; next } { print "na", "na", $3 }'

or
$ awk '{ if ($3 ~ /pattern/) { print $1, $2, $3 } else { print "na", "na", $3 } }'

Reply to this comment

Mike Adolphs Permalink


May 02, 2009, 16:34
Just wanted to let you know that this article provides a solution for a problem I've faced for the last couple of hours. Great work and thanks to you!
Reply to this comment

Javier Permalink
March 10, 2010, 18:05
Hi everybody,
I've a file that looks like:
000000
87 62 90 180 1.40679 1.60570860e-01
000000
88 62 89 179 1.39871 1.76044390e-01
000000
88 64 86 172 1.34657 1.50280803e-01
000000
87 63 88 176 1.38235 1.94590941e-01
000000
116 45 64 129 1.01130 1.18465826e-01
88 63 87 175 1.36837 1.46118164e-01
000000
87 61 93 187 1.46723 1.99260086e-01
The lines containing 0's can be thought as being delimiters. I need to find between the each pair of delimiters, which line has the highest value in the last column and return it for further
processing. Does anybody could shed some light on it?
Best regards,
Reply to this comment

marco Permalink
June 22, 2010, 12:51
great page...
might and in an (NF==4) to the IP address validation exit logic.
Reply to this comment

AwkNewbie Permalink
October 03, 2010, 21:24
Great awk tips. Now I have a question. What should be the command if I want to delete a range pattern, ie. if I want to delete all the lines from [Pattern2] to the first blank line for the file
given below:
[Pattern1]
Some lines
Goes here
[Pattern2]
Some more lines
[Pattern3]
Goes on...

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

12 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Reply to this comment

Kundan Permalink
March 07, 2011, 18:42
I have input file which has data somewhat line this, call details are in a XML file. Each call data ends with "
Reply to this comment

Joe B Permalink
June 10, 2011, 18:45
Very useful article and comments!
I have my own awk dilemma...
I'm trying to identify (and print) records from a file where the 15th & 16th bytes of a record = '02'. I've been searching for a solution but it appears most awk commands of this type reference a
field $1, $2, etc.
Any ideas on how to write this? The file contains several layouts and for these specific records they are fixed length.
Reply to this comment

IF_Rock Permalink
September 23, 2011, 20:18
String constants set using apostrophes in gawk?
Reply to this comment

Amiya Permalink
October 26, 2011, 12:02
Hi All,
Can you please tell me the awk command to collect 10 lines after the search pattern.
thanks
Amiya
Reply to this comment

Jotne Permalink
August 14, 2013, 07:39
Print 2 lines before and 3 after "pattern"
awk '{a[NR]=$0} $0~s {f=NR} END {for (i=f-B;i<=f+A;i++) print a[i]}' B=2 A=3 s="pattern"<\code>
grep -A3 -B2 "pattern"<\code>

Reply to this comment

Amiyaranjan Sahoo Permalink


December 22, 2011, 12:28
Hi All,
Can you please tell me how to print 10 lines after/before the search string in HP UX.
Regardsm
Amiya
Reply to this comment

unix awk command Permalink


February 02, 2012, 11:07
Thanks for the post. A worth reading article on awk.
Reply to this comment

pecival Permalink
July 23, 2012, 19:03
you said
awk '{sub(/pattern/,"foobar")}1'
is the equivalent to
sed 's/pattern/foobar/'
..not exactly..AFAIK the sed part should have /g to apply the replace to all matches (not just the first one)..It's just a detail, but let's be precise ;)

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

13 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

(I hope I'm not saying nonsense)


Reply to this comment

ohno Permalink
April 03, 2013, 11:08
AFAIK gsub() would be the equivalent to s///g. sub() only substitutes the first occurence.
Reply to this comment

Jotne Permalink
November 25, 2012, 10:56
awk '/foo/ || /bar/'
more simple
awk '/foo|bar/'
Reply to this comment

Vadim Bogulean Permalink


March 02, 2013, 09:15
Hi and thanks for your tips.
I was actually looking a way to print certain number of lines after searching a line in a file.
Based on the tips from 'Print lines using patters' I could elaborate one for my needs. Thought you could add it as well for others.
awk "{cnt-=1;if(cnt<=0)p=0;}/$1/{p=1;cnt=$2}p" $3
where $1, $2 $3 to be replaced with :
$1 - Your search pattern,
$2 - Number of lines to display (including searched pattern)
$3 - Your input file
i.e
$ awk "{cnt-=1;if(cnt<=0)p=0;}/Error:/{p=1;cnt=2}p" file
file content:
Error:
Error # 1
Warning:
Warning # 2
Error:
Error # 3
Result would be:
Error:
Error # 1
Error:
Error # 3
Reply to this comment

sabith Permalink
April 16, 2013, 04:36
I have two folders named 'check' in two places. Both will have same folders but the files of each folder may differs. I want to run a script to find the difference between the folders with same
name in each 'check' folder then I have to redirect the difference to a file. Please anyone help me..
Reply to this comment

colossus Permalink
October 02, 2013, 02:44
"""eg, if "FOO5\nFOO6" is found, the file "out5" will not be created"""
should be "out6" will not be created, right?
Reply to this comment

mug896 Permalink
December 30, 2013, 01:30
how about this one for IPv4 check
awk -F '[.]' 'function ok(n) {
if (n ~ /^[0-9][0-9]?[0-9]?$/) {
return (n>=0 && n<=255)
}

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

14 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

}
{exit (ok($1) && ok($2) && ok($3) && ok($4))}'
Reply to this comment

mug896 Permalink
December 30, 2013, 03:35
awk '!($0 in a) {c++;a[$0]} END {exit(c==NR/2?0:1)}' file1 file2
is not working..
test with this file contents
$ cat d3.txt
.[error]
id=AAA
id=CCC
.[error]
id=AAS
.[error]
id=ABC
$ awk '!($0 in a) {c++;a[$0]} END {print(c==NR/2?0:1)}' d3.txt d3.txt
1 <---- return 1 not 0 !!!
Reply to this comment

CKP Permalink
April 28, 2014, 14:30
I have an input file "myfile" and a shell variable "VAR" whose
contents are shown below:
# cat myfile
Hello World
Hello Universe
# echo $VAR
World
I need to process all lines in "myfile" which contains pattern "World"
using awk. It works if i do as shown below:
# awk '/World/ { print $0 }' myfile
But i could not use VAR to do the same operation. I tried the
following even knowing that these will not work:
# awk '/$VAR/ { print $0 }' myfile
and
# awk -v lvar=$VAR '/lvar/ { print $0 }' myfile
and
# awk -v lvar=$VAR 'lvar { print $0 }' myfile
Please let me know how to match the contents of VAR in awk.
Thanks in advance
Reply to this comment

Curtis Wilbar Permalink


May 07, 2014, 16:21
This will work:
awk -v lvar="${VAR}" 'match($0, lvar) { print $0 }' myfile
Reply to this comment

atehwa Permalink
October 14, 2014, 13:03
In the section "Check whether two files contain the same data", there is the claim that the awk solution is O(n). However, this is dependent on the associative array entry creation and lookup
being amortised O(1). Surprisingly many utilities don't use such associative arrays but instead have O(n) behaviour for sufficiently large data. This can be caused by e.g. static hashtables or
hashtables that resize by a constant amount.
If the hashtable implementation _is_ good, then the solution's linearity depends on loading all data into memory. If insufficient memory is available, sort is often a faster alternative. However,
this depends on many factors.
Reply to this comment

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

15 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Leave a new comment


Name:
E-mail:

(why do I need your e-mail?)

It would be nice if you left your e-mail address. Sometimes I want to send a private message, or just thank for the great comment. Having your e-mail really helps.
I will never ever spam you.
Twitter:

(Your twitter name, if you have one. (I'm @pkrumins, btw.))

Website:
Comment:

Comment Help
* use <pre>...</pre> to insert a plain code snippet.
* use <pre lang="lang">...</pre> to insert a syntax highlighted code snippet.
For example, <pre lang="python">...</pre> will insert Python highlighted code.
* use <code>...</code> to highlight a variable or a single shell command.
* use <a href="url" nospam>title</a> to insert links.
* use other HTML tags, such as, <b>, <i>, <blockquote>, <sup>, <sub> for text formatting.
Type the word "linux_100":

(just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.

Advertisements
About the site:

Peteris Krumins' blog about programming, hacking, software reuse, software ideas, computer security, google and technology.
Reach me at:

Or meet me on:
Twitter
Facebook
Plurk
more
GitHub
LinkedIn
FriendFeed

Google Plus
Subscribe to my posts:
Subscribe through an RSS feed:
(what is rss?)
Subscribe through email:

Enter your email address:

Delivered by FeedBurner

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

16 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Server Sponsors
I am being sponsored by Syntress since 2007! They bought me an amazing dedicated server to run catonmat on. If you're looking web services in Chicago area, I highly recommend the
Syntress guys!
My Amazon Wish List
I love to read science books. They make my day and I get ideas for awesome blog posts, such as Busy Beaver, On Functors, Recursive Regular Expressions and many others.
Take a look at my

Amazon wish list, if you're curious about what I have planned reading next, and want to surprise me. :)

My Books
Awk Programming Book
Sed Programming Book
Perl Programming Book
My Other Websites
Free Science Online
Free Science Videos
Top Ten Articles:
Top Ten One-Liners from CommandLineFu Explained
My Job Interview at Google
Famous Sed One-Liners Explained, Part I: File Spacing, Numbering and Text Conversion and Substitution
MIT's Introduction to Algorithms, Lectures 1 and 2: Analysis of Algorithms
Famous Awk One-Liners Explained, Part I: File Spacing, Numbering and Calculations
The Definitive Guide to Bash Command Line History
Low Level Bit Hacks You Absolutely Must Know
Working Productively in Bash's Vi Command Line Editing Mode (with Cheat Sheet)
Turn any Linux computer into SOCKS5 proxy in one command
A HTTP Proxy Server in 20 Lines of node.js Code
See all top articles
Top Ten Downloads:
bash history cheat sheet (.pdf) (191,247)
awk cheat sheet (.pdf) (184,630)
perl1line.txt (171,859)
sed stream editor cheat sheet (.pdf) (138,000)
perl's pack/unpack and printf cheat sheet (.pdf) (129,147)
screen cheat sheet (.pdf) (123,966)
bash vi editing mode cheat sheet (.pdf) (116,873)
perl's special variable cheat sheet (.pdf) (111,881)
awk cheat sheet (.txt) (110,529)
the bill gates song.mp3 (musical geek friday #8) (94,797)
See all downloads
Recent Articles:
cards.dll - a fun dll that came with windows
Creating outgoing bandwidth summary for Rackspace cloud servers
A new browsing URL scheme for Browserling
How to remember ./configure script arguments a year later
Creating tables with console.table in Chrome
All these bash redirections are equal
Seven years of blogging
splice() can be used to push(), pop(), shift() and unshift() and more
Annoying key combination that you should unmap in Linux
How to run the previous command with sudo quickly
See more detailed list of recent articles
Article Categories:
Awk Programming (8)
Browserling Startup (27)
Cheat Sheets (13)
Computer Science (9)
Hacker's Approach (8)
Howto (12)
Idea for Later (1)
Interviews (5)
Introduction to Algorithms (15)
Linear Algebra (6)
Mathematics (1)
Misc (17)
Musical Geek Friday (17)
Node.js Modules (15)
Perl Programming (16)
Programming (36)
Projects (13)

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

17 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

Security (3)
The New Catonmat (1)
Tools (1)
Unix Shell (29)
Video Lectures (17)
Visual Math Friday (1)
See more detailed category information
Article Archive:
December, 2014 (1)
November, 2014 (1)
October, 2014 (2)
September, 2014 (1)
August, 2014 (1)
July, 2014 (1)
June, 2014 (1)
May, 2014 (1)
April, 2014 (1)
March, 2014 (3)
February, 2014 (3)
January, 2014 (5)
December, 2013 (1)
November, 2013 (1)
October, 2013 (1)
September, 2013 (1)
August, 2013 (1)
July, 2013 (1)
June, 2013 (1)
May, 2013 (1)
April, 2013 (1)
March, 2013 (1)
February, 2013 (2)
January, 2013 (4)
December, 2012 (1)
November, 2012 (3)
October, 2012 (4)
September, 2012 (3)
August, 2012 (2)
July, 2012 (2)
June, 2012 (1)
May, 2012 (4)
April, 2012 (4)
March, 2012 (2)
February, 2012 (1)
January, 2012 (4)
December, 2011 (15)
November, 2011 (3)
October, 2011 (2)
September, 2011 (2)
August, 2011 (3)
July, 2011 (1)
June, 2011 (2)
May, 2011 (1)
April, 2011 (1)
March, 2011 (2)
February, 2011 (1)
January, 2011 (1)
December, 2010 (2)
November, 2010 (1)
October, 2010 (2)
September, 2010 (1)
August, 2010 (2)
July, 2010 (2)
June, 2010 (2)
May, 2010 (2)
April, 2010 (2)
March, 2010 (5)
February, 2010 (5)
January, 2010 (7)
December, 2009 (6)
November, 2009 (6)
October, 2009 (2)
September, 2009 (3)
August, 2009 (2)
July, 2009 (4)
June, 2009 (1)
May, 2009 (1)
April, 2009 (1)
March, 2009 (2)
February, 2009 (7)
January, 2009 (4)

1/30/2015 5:27 PM

10 Awk Tips, Tricks and Pitfalls - good coders code, great reuse

18 of 18

http://www.catonmat.net/blog/ten-awk-tips-tricks-and-pitfalls/

December, 2008 (8)


November, 2008 (7)
October, 2008 (4)
September, 2008 (5)
August, 2008 (9)
July, 2008 (14)
June, 2008 (4)
May, 2008 (5)
April, 2008 (8)
March, 2008 (3)
February, 2008 (1)
January, 2008 (1)
November, 2007 (2)
October, 2007 (3)
September, 2007 (5)
August, 2007 (10)
July, 2007 (9)
See more detailed list of all articles
Advertisements

Advertisements
Alexa stats

Friends
Alastair McGowan-Douglas
James Halliday
Madars Virza
simcop2387
Mr. Waldner
SymKat
f00li5h
amix
Info
catonmat's source code.
Privacy Policy
Advertise on catonmat
If you are interested in advertising on catonmat.net, contact me.

1/30/2015 5:27 PM

Anda mungkin juga menyukai