Author: Michael Stutz
phone
or tel
that calls grep
to output lines that match whatever arguments you give. You can improve on that method to create a personal contact manager with surprising speed and power.
My requirements for an address book and contact manager are simple. I just want to be able to search and view records whenever I need them, from the command line and a text editor. I don’t want to have to start up one of the many standalone applications for this purpose, which all have their own sets of dependencies, file formats, and editing commands. And since I work on a single system and share the data with no one, rigging up a home LDAP (Lightweight Directory Access Protocol) setup is overkill.
Furthermore, this contact manager should be usable whether I happen to be in X or at a console, and perfectly accessible over a slow text-only network line. It should let me cut and paste addresses and contact information from the Web, email, and any other application I might run. There should be no forms to have to complete for each record, and no concept of “required fields” — each record should be able to contain as much, or as little, information as I happen to have.
With a plain-text file and a few handy tools like awk
, you can easily accomplish all of the above.
The contacts file
The first step is to make a new file (call it something like “contacts”) and begin adding records to it in your favorite text editor.
Records have to be delimited somehow; I use ###
on a line by itself. Format the records themselves however you like, with name and address and whatever information you have. I used to keep a completely free-form contacts file, so that each record contained completely unformatted data in whatever way that I happened to get it, but this practice quickly shows its limitations — I’ve found that it helps immensely to label certain fields, such as telephone number and email address. I use this format:
NameAddress Phone: phone number Fax: fax number Email: email address Comments: additional information
As an example, a few records might look like this:
Acme Industries, Inc. 4211 E Broadway New York, NY 10026 Phone: (212) 555-1032 Fax: (212) 555-1038 Email: acme@example.net ### capri pizza Phone: 555-8250 ### jane smith Phone: 555-3104 Email: jsmith@example.nyu.edu Comments: friend of susan's
Searching, browsing, and exporting records
You can search and browse the contacts file in any text editor, of course, but from the command line the tools of the hour are grep
in all its variants and awk
.
fgrep
outputs single lines of the file that match a string you give, and is good for when you just want to see if you have such-and-such a record in your file. Use the -i
option to do a case-insensitive search — for instance, here’s how to see if you have contact information for Acme Industries:
$ fgrep -i 'acme industries' contacts Acme Industries, Inc. $
The output gave the name — but you want the phone number too. Output the search with a few lines after the match with the -A
option:
$ fgrep -i -A5 'acme industries' contacts Acme Industries, Inc. 4211 E Broadway New York, NY 10026 Phone: (212) 555-1032 Fax: (212) 555-1038 Email: acme@example.net $
And here’s where using labels really pays off. When you need, say, all the email addresses that have “nyu.edu” in them, you can find them with a plain grep
command:
$ grep '^Email:' contacts | fgrep 'nyu.edu'
Harvesting the actual addresses themselves is also a trivial matter:
$ grep '^Email:' contacts|egrep -o '[^ ]+$'
You can use awk
to output entire records containing a particular match. The simplest way is to change the awk
record separator, RS
, to ###
and then enclose the pattern to match in slashes. For example, here’s how to export all records containing the string “acme” somewhere in the record:
$ awk 'BEGIN { RS = "###" } /acme/' contacts Acme Industries, Inc. 4211 E Broadway New York, NY 10026 Phone: (212) 555-1032 Fax: (212) 555-1038 Email: acme@example.net $
You can put the command in a script called address
that takes a search string as an argument:
#!/bin/sh awk 'BEGIN { RS = "###" } /'$*'/' ~/contacts
Then you’ll get all of the records containing the string you search for, separated by newlines, when you call address
:
address smith address nyu.edu address 90028
Because the file has labels, you can limit your search to them. For example, you can search for all email addresses that have “smith” in them, and output the entire records:
$ awk 'BEGIN { RS = "###"; FS = "Email: " } ($2 ~ "smith") { print $0 }' contacts
You can use the same awk
pattern to do any number of things. For instance, in conjunction with the grep
examples above you can output all the email addresses in records that have “friend” in the comment field:
$ awk 'BEGIN { RS = "###"; FS = "Comments: " } ($2 ~ "friend") { print }' contacts | grep '^Email:' | egrep -o '[^ ]+$'
Adding and importing records
Adding records to your contacts file is easy. The file doesn’t need to be sorted, so append new records by either editing the file in a text editor or using redirection on the command line:
$ cat >> contacts
Rarely do I actually type out any new contact information myself — that only happens when I’m transcribing something from paper, or when I’m getting a number from someone on the phone. Nine times out of 10 I’m just cutting and pasting the text from the Web or email into an editor window that has the contacts file open. It’s painless and fast — there are no forms to have to fill out for each part of the record. But you have to keep two things in mind: separate the records with hash marks, and insert labels for numbers, email, and comment fields, if you want to use them.
If you already have a set of address records formatted some other way, awk
can import it so that it’s in the right format.
Let’s say you have a file named address.txt where all the records are kept one to a line in this common format:
lastname,firstname,address,city,state,zip,phone,email
Here’s an awk
one-liner to take that input and spit it out into the bottom of the contacts file, in just the right format:
$ awk 'BEGIN { FS = "," } { print "n###nn" $2, $1, "n" $3 "n" $4 ", " $5, $6, "nPhone: " $7, "nEmail: " $8 }' address.txt >> contacts