In my “free time” I’ve been idly trying to become proficient at the *nix command line. As told by my previous “converting to Linux” article, I’m trying to make the shift over to Ubuntu full-time, but for a Microsoft-head such as myself, the move isn’t exactly instantaneous.

So, in an attempt to log my efforts, I’m going to start posting little pieces of information that learn/figure out. Today we start with a light lesson in grep.

Side-note(s)
While I am trying to make the switch over to Linux, I find it unfair to my clients to be uncomfortable on my laptop while working billable hours. So this particular lesson will consist of Linux commands, but are run via Cygwin under windows. For those who don’t know, Cygwin is an implementation of the Linux command line and tools that run under windows. Read more about it on the Cygwin website or at the wiki.

My example is at the bash command line. If you’re using a different command line, the methodology may change, I don’t really know (insert lack of Linux knowledge here).

Also, grep is an unbelievably powerful tool. Books upon books have been written on it. This is in no way the only use of grep, nor is it a comprehensive account of using grep in this scenario. I’m just laying the groundwork. The internets (sometimes called blagosphere, tubes, whatever you may like) are a wonderful place, do some more research…

Scenario
I’m working on a website where we had to find all files containing the word “Leads” and change it to “Prospects” (clients… they ask for such weird stuff…). In the project directory, there are a bunch of common website files (php, html, css, js, etc…). But this particular project folder is also maintained by Subversion version control. On windows, that means there is a hidden .svn folder in every directory to maintain the changes to that file. This will make sense in a minute.

Technique – Step 1 – Grep
The manual page for grep says to do a simple search through files is something like this:

grep -R "search value" ./

translation: find every file within my directory and its subdirectories containing this search value.

Technique – Step 2 – | [pipe]
There is a rather handy thing called “piping.” It allows you to run more than one command at once, but also run each subsequent command on the previous commands output. Semi-unrelated example:

ls -la | grep .txt

ls -la will give you a directory listing. What this statement then does is say “ok, with the output of the directory listing, give me only lines containing .txt” giving you a list of all text files in a directory.

ls -la | grep .txt | wc -l

this does the same thing, but wc -l (that is a lowercase L) means “word count, lines only” showing you how many text files you have in your directory.

Back to the task at hand: find all files containing the word Leads.

grep -R "Leads" ./

Output:

$ grep -R "Leads" ./
././.svn/text-base/Popup.php.svn-base:    case 'Leads':
./.svn/text-base/Popup.php.svn-base:            require_once("modules/$currentModule/Leads.php");
./.svn/text-base/Popup.php.svn-base:            $focus = new Leads();
./.svn/text-base/README.txt.svn-base:12. 131  - Sorting Name in Leads
./.svn/text-base/README.txt.svn-base:49. 1161406: Assigned ToUser in Leads can be Assigned to User
./.svn/text-base/README.txt.svn-base:16. FORUM:1276 - Converting Leads and assigning to user
./.svn/text-base/README.txt.svn-base:20. FORUM:1559 - Tasks not working in Leads
./.svn/text-base/README.txt.svn-base:31. SF1095038 - Import Leads - No Mapping Fields

That seems pretty useless because this is all information contained in the .svn files. Eventually, the appropriate info will be contained in there, but make the machine do the work. We want all files containing “Leads” that aren’t in a .svn directory. The -v flag is your friend… It means “find things that don’t contain this.” Code:

grep -R "Leads" ./ | grep -v ".svn"

Output

$ grep -R "Leads" ./ | grep -v "svn"
./include/js/general.js:           if(record_id != '' && module[0] == "Leads")
./include/js/general.js:           if(task_recordid != '' && task_module[0] == "Leads" )
./include/language/en_us.lang.php:'LNK_IMPORT_LEADS' => 'Import Leads',
./include/language/en_us.lang.php:'SINGLE_Leads' => 'Lead',
./include/language/en_us.lang.php:'COMBO_LEADS' => 'Leads',
./include/language/en_us.lang.php:'Leads' => 'Prospects',

See the en_us files there? That’s all I’m worried about, so I can do another pipe to only view those files:

grep -R "Leads" ./ | grep -v ".svn" | grep "en_us"

Output

$ grep -R "Leads" ./ | grep -v "svn" | grep "en_us"
./modules/Emails/language/en_us.lang.php:'LBL_LEAD_TITLE'=>'Leads',
./modules/HelpDesk/language/en_us.lang.php:'Leads'=>'Lead',
./modules/Home/language/en_us.lang.php:'LBL_LEADS_BY_SOURCE'=>'Leads By Source',
./modules/Home/language/en_us.lang.php:'LBL_LEADS_BY_STATUS'=>'Leads By Status',
./modules/Leads/language/en_us.lang.php:'LBL_IMPORT_LEADS'=>'Import Leads'

My task is complete. I’ve gotten all the translation files that contain the word Leads, and I can either manually edit them, or use the command line to edit them, but that’s another lesson.

Optional Step 3 – >>

I want to make a checklist that I can print and have on my desk while i’m working with these files. There’s a simple way to do this:

grep -R "Leads" ./ | grep -v "svn" | grep "en_us" > /path/to/file.txt

This will take all the output and drop it in the file I specified. If you use one >, it will create the file if it doesn’t exist, and if it does exist, replace all content in that file with the output from our grep. If you use two >>, it will create if it doesn’t exist and it will append the text if it does exist.

I know it’s a sloppy example, but that’s how I achieved my goal, and it was MUCH faster than finding all the translation files in the application and doing it by hand.