Old Guy New Trick

An old guys journey to learn how to code.

zshell, zshell by the zshore

Author: John on February 01, 2016

While working on a feature recently I found myself executing the following command at the command line to get a listing of files I would want to run through cucumber to make sure I didn't break anything with my new change: 

fgrep -rl 'I follow "Downloads"' features/*/*.feature

In case that looks foreign to you, let me summarize what I was doing.  Hopefully you are familar with the basic use of grep.  One could use grep -F as it is the same as fgrep, however I am used to using the fgrep syntax. Following the command, fgrep, we have two flags which we initiate with the dash (-).  These flags are r for recursive and l for listing the files that contain what we are looking for.  In my example above, I want a listing of all files that contain:  I follow "Downloads".  

The last part of the command is a location where I want to start searching - features/*/*.feature.  Using this path, along with the -r argument to fgrep, we will search for I follow "Downloads" in the features directory and all subdirectories, in files that end in .feature.  No sense in searching our step definition files.

The result of running the command fgrep -rl 'I follow "Downloads"' features/*/*.feature is a list of all *.feature files that contain the requested string.  But this is only a part of what I need to do.  After I have a list of the files, I then needed to type cucumber and then copy and paste all of the found files so that I could run the related tests.  

If this were a one time deal, I would have left things alone.  But I knew that I would be running these tests again, and probably other tests in a similar fashion.  So I had to find a cure for my laziness, err, efficiencies.  Enter using our shell, in my case zshell (zsh) to help us automate things.  Yes we can create mini programs/scripts using the shell.

Let's review what I was trying to do.  I want to search in all *.feature files in my project for a particular cucumber step, I follow "Downloads".  I want to collect these files and then run the command cucumber for each file that I have collected.  Two words should have stood out to you - 'collect' and 'each'.

We saw earlier how I could use fgrep to find the files that contained my criteria string.  So we can re-use that snippet.  But we need to use that syntax with a little bit of zshell syntax in order to create an array.  Take a look at the code below:

feature_files=("${(f)$(fgrep -rl 'I follow "Downloads"' features/*/*.feature)}")

You can test that the array has elements by using something like this:

echo $feature_files[1]   #list one element of the array
echo $feature_files      #list all of the elements in the array

Ok, we are getting closer.  We now have a nice collection of files stored in our array - $feature_files.  Now we just need to loop (iterate) over the array of files, excecuting the command cucumber for each file.  (Note: I have an alias called cuc which is the same as cucumber - just less typing.)  We can use the following zshell syntax (works with other shells as well,) to wrap up our automation task:

for feature in $feature_files; do
  cuc $feature

Pretty neat, huh?  One day I may take this a bit further and create a zshell executable script that can take two arguments - path and search string.  But for now, this works just fine.

Learn Something New Everyday


Last Edited by: John on February 01, 2016