- Common Loki Misconfigurations
- Iterating Through a List in Ink
- Debugging Misconfigured Container Networks
- Minimum Viable EC2 in Terraform
- Storylets in Ink
- Interactive Fiction Tooling Overview
- In-Place Resizing for Digitalocean Droplets
- Unity Demonstrates the Importance of FOSS
- Target Labels in Prometheus
- My View of AI is the Same
- Verify DNS Ownership with TXT Records
- Sane Droplet Defaults
- Editing Made Easy with Vim
- Gatsby Gotchas
- Concatinating Default AWS Tags in Terraform
- Easily Updating the Default Github Branch
- Lifetimes in Rust
- Checking for Bad Links
- Maybe TypeScript and React is Bad
- Static Asset Management in React
- Bundler Down Time
- Using React Context for Localization
- JS Implementation of a Sticky Footer
- Custom Aliases
- Trying Out the 7drl Challenge
- Trash Opinions
- Building Your First Program in Rust
- Fixing mongod reports errors related to opening a socket
- Improving Open Source Maintenance
- Technical Interviewing Tips
- Housekeeping Note
- Dynamic Programming Basics
- The Oddity of Naming Conventions in Programming Languages
- An Experiment Using Machine Learning, Part 3
- Debugging with grep
- An Experiment Using Machine Learning, Part 2
- An Experiment Using Machine Learning, Part 1
- The Value of while
- National Day of Civic Hacking
- OpenAI and the Future of Humanity
- Creating a Whiteboard App in Django
- Creating Meaningful, Organized Information
- Towards A Critique of Social Media Feeds
- Setting up Routes in Django
- Developing a Messaging Component for Code for SF
- Dream Stream 2.0
- Keyed Collections in Javascript: Maps and Sets
- Blog Soft Relaunch
- Scraping with Puppeteer
- Looking Ahead to Dream Stream 2.0
- Solving West of Loathing's Soupstock Lode Puzzle
- Installing Ubuntu
- Interview with David Jickling Evaluation
- Compare Text Evaluation
- Dream Stream Evaluation
Debugging with grep
There are a couple of standard pieces of advice for debugging software:
- Create break points to figure out where something goes wrong
- Create strategic print statements to figure out what is happening
- Use the scientific method to reason about things
This is all very good advice, and how I approach debugging as well. However I have an additional piece of advice to give new developers that are trying to determine the source and solution to a bug: utilize recursive grep queries.
What is grep, and why should I care?
grep, somewhat unhelpfully, stands for “global regular expression print”. In plain English it is a command line Unix tool that uses a search pattern (i.e. a word or regular expression) to find instances of that expression. Most text editors have a find tool, so if you just wanted to use grep to find a word in a particular document without using regular expressions, you might be wondering about the value proposition. However the recursive flag is where grep truly shines. That allows you to search all files starting from the root directory into all the subfolders for a particular search pattern. This is incredibly powerful when you’re dealing with a large, complex directory.
As software engineers we are encouraged to separate our code into discrete modules. This makes it easier to understand the interface of a piece of software, but it can come at the cost of understanding the program’s flow of control. It is not uncommon to create a library of objects, each with an assortment of methods. And those methods might be called on by other libraries, and at that point if there is a bug in the code it could be very deeply nested, and not at all obvious where you should look to fix it. This is where the recursive grep query comes to the rescue, and allows you to follow the chain of calls so that you can begin to understand the control flow.
So lets say you’ve utilized break points and print statements to locate the point in the program where the bug is being generated, but all you have is a called method, but you have no idea where to find this method. In the root directory you can run:
grep methodName -r
This will create a list of instances and file names where your methodName
comes up. At that point you can examine the files, find where the actual method is defined, and figure out what is going on. Sometimes that will lead to another method you have to look up, and so you repeat the process until you are able to generate an understanding of what is actually happening when a particular method is called.
Hopefully the method you are looking up has a unique name. But of course there is always the possibility that you are looking into a method with a generic name. I encountered this issue during my most recent debugging experience where I had to lookup a method called addItem
. Well, it turns out the libraries and modules for this project had tons of methods called addItem
so my recursive grep query slowly generated a ton of useless results. In those instances, you need to figure out some way to limit your results. Luckily there are flags that allow you to exclude directories. So, for example, when I was querying addItem
, I wrote:
grep addItem -r --exclude-dir=node_modules
This excluded all the npm dependencies the project was using, and eliminated thousands of results down to two! With a couple of thoughtful queries, recursive grep searches is one of the most powerful debugging tools I know of. As you get more comfortable with grep and other tools available in the Linux command line you will be able to accomplish even more. For example, you could output your grep search into a file that can be referenced there instead of the standard output on the terminal:
grep -Hn [0-9] file_name.txt > search_results.txt
Here we are using the -Hn
flag which will prefix our output with the filename and line number. We are using a regular expression for our search pattern that will look for any digits, and it outputs the file to search_results.txt.
UPDATE 6/24/2019
I recently discovered that the way grep is implemented on MacOS differs slightly. To do a recursive search in a Mac environment you also need to specify the relative path where your search is happening. So to search from your current directory path:
grep foo -r .