$ grep Essentials

Cover Image for $ grep Essentials

$ grep is often used when parsing logs and other files containing a bunch of text. But, a blog post with snippets of random logs doesn't sound fun to read, and many developers are familiar with JavaScript. Let's practice some common grep use cases with uncommon files, a tiny JavaScript program.

If you'd like to $ grep along, you can clone the source files from the $ grep essentials companion code repo.

Scenario

Presume we're in a predicament,

  1. We don't have a text editor
  2. We can't figure out how to use VIM
  3. We're eager to interrogate a few odd JavaScript files for specific text (and emojis!)

Our directory contains index.js, trees.js, leaves.js, and barnYardAnimal.js.

index.js
const { isTree } = require('./trees')
const { isLeaf } = require('./leaves')
const { isBarnYardAnimal } = require('./barnYardAnimal')

console.log(`\nIs 🌲 a tree? ${ isTree('🌲') }`) // true
console.log(`Is 🍂 a tree? ${ isTree('🍂') }`) // false
console.log(`Is 🐄 a tree? ${ isTree('🐄') }\n`) // false
console.log(`Is 🌲 a leaf? ${ isLeaf('🌲') }`) // false
console.log(`Is 🍂 a leaf? ${ isLeaf('🍂') }`) // true
console.log(`Is 🐄 a leaf? ${ isLeaf('🐄') }\n`) // false
console.log(`Is 🌲 a barn yard animal? ${ isBarnYardAnimal('🌲') }`) // false
console.log(`Is 🍂 a barn yard animal? ${ isBarnYardAnimal('🍂') }`) // false
console.log(`Is 🐄 a barn yard animal? ${ isBarnYardAnimal('🐄') }\n`) // true
trees.js
function isTree(tree) {
  const trees = ["🌲", "🌳", "🌴", "🎄", "🎋"];

  return trees.includes(tree);
}

module.exports = { isTree };
leaves.js
function isLeaf(leaf) {
  const leaves = [ '🍁', '🍂', '🍃' ]

  return leaves.includes(leaf);
}

module.exports = { isLeaf }
barnYardAnimal.js
function isBarnYardAnimal(animal) {
  const barnYardAnimals = ["🐑", "🐐", "🐖", "🐄", "🐓"];

  return barnYardAnimals.includes(animal);
}

module.exports = { isBarnYardAnimal };

Basic $ grep Usage

The $ grep utility provides a way to search files for specific text. Let's try it out!

Searching for text in a file with $ grep

Hmm, I wonder if the barnYardAnimal.js contains a function called isBarnYardAnimal. We can quickly determine this with $ grep,

The command,

grep isBarnYardAnimal barnYardAnimal.js

yields two matches,

function isBarnYardAnimal(animal) {
module.exports = { isBarnYardAnimal }

In this case, we're searching for the string "isBarnYardAnimal" in the file barnYardAnimal.js.

Searching for emojis in a file with $ grep

$ grep also support emoji searches! Sure, the real world use case is minimal, but it's fun -> so let's find out if we include the pig emoji 🐖 in barnYardAnimal.js.

The command,

grep 🐖 barnYardAnimal.js

yields,

const barnYardAnimals = [ '🐑', '🐐', '🐖', '🐄', '🐓' ]

In this case, we're searching for the emoji string 🐖 in the file barnYardAnimal.js.

Searching for text in multiple files with $ grep

Let's find out if our flora related files export any functions.

The command,

grep exports leaves.js trees.js

yields,

leaves.js:module.exports = { isLeaf }
trees.js:module.exports = { isTree }

In this case, we're searching for the string "exports" in two files, leaves.js and trees.js.

Searching for text in a directory with $ grep

We can use the $ grep command's -r option to recursively serach subdirectories. Let's try it out to determine which of our files contains console.log statements.

The command,

grep -r console.log .

yields,

./index.js:console.log(`\nIs 🌲 a tree? ${ isTree('🌲') }`) // true
./index.js:console.log(`Is 🍂 a tree? ${ isTree('🍂') }`) // false
./index.js:console.log(`Is 🐄 a tree? ${ isTree('🐄') }\n`) // false
./index.js:console.log(`Is 🌲 a leaf? ${ isLeaf('🌲') }`) // false
./index.js:console.log(`Is 🍂 a leaf? ${ isLeaf('🍂') }`) // true
./index.js:console.log(`Is 🐄 a leaf? ${ isLeaf('🐄') }\n`) // false
./index.js:console.log(`Is 🌲 a barn yard animal? ${ isBarnYardAnimal('🌲') }`) // false
./index.js:console.log(`Is 🍂 a barn yard animal? ${ isBarnYardAnimal('🍂') }`) // false
./index.js:console.log(`Is 🐄 a barn yard animal? ${ isBarnYardAnimal('🐄') }\n`) // true

In this case, the -r options denotes we're recursively searching for the string "console.log" in our current directory, denoted with ..

Excluding files from $ grep search

Uh oh, it looks like cloning this project from GitHub included a README.md file. Our README.md includes a handful of the emojis in our JavaScript files. Imagine we want to search for an emoji in our JavaScript files and not our readme. To do so, we exclude the README.md file while searching our current directory.

The command,

grep 🌲 -r . --exclude README.md

yields,

./index.js:console.log(`\nIs 🌲 a tree? ${ isTree('🌲') }`) // true
./index.js:console.log(`Is 🌲 a leaf? ${ isLeaf('🌲') }`) // false
./index.js:console.log(`Is 🌲 a barn yard animal? ${ isBarnYardAnimal('🌲') }`) // false
./trees.js:  const trees = [ '🌲', '🌳', '🌴', '🎄', '🎋' ]

In this case, we're using the previously mentioned -r option to recursively search our current directory for the 🌲 emoji. We introduce the --exclude option to, you guessed it, exclude the README.md file from our search.

Finding files with a ;

Close inspection of our files reveals we're implicitly relying on JavaScript's automatic semicolon insertion (ASI). Let's find out if we've included any semicolons in our directory. To do this, we introduce the

The command,

grep -r . -e \;

yields a line containing a semicolon,

./leaves.js:  return leaves.includes(leaf);

In this case, we're again using the -r option to recursively search our current directory for a ; character. The new -e options allows us to search using a regular expression, \;. Our search would otherwise fail without the -e option.

Case insensitive searches with $ grep

By default, $ grep is case sensitive. Let's find all occurrences of the word animal in our directory regardless of the word's case. Doing this with $ grep is straightforward, we simply introduce the -i option. This instructs the $ grep command to ignore the case, performing case insensitive matching.

The command,

grep -i animals -r .

yields two matches in barnYardAnimal.js,

./barnYardAnimal.js:  const barnYardAnimals = [ '🐑', '🐐', '🐖', '🐄', '🐓' ]
./barnYardAnimal.js:  return barnYardAnimals.includes(animal)

Outputting file Names with $ grep

What if we only want our $ grep command to output file names? We can easily do this using the -l option. Let's find all of the files that export a function in our directory.

The command,

grep exports -r . -l

yields,

./barnYardAnimal.js
./trees.js
./leaves.js

Outputing lines after a match with $ grep

Imagine we want some additional context when outputting $ grep matches. We can do this using the -A options. The -A option takes a single argument, num, which is the number of lines to output after a match.

The command,

grep function -r . -A 4

yields 4 lines after each match for the word "function",

$ ./barnYardAnimal.js:function isBarnYardAnimal(animal) {
$ ./barnYardAnimal.js-  const barnYardAnimals = [ '🐑', '🐐', '🐖', '🐄', '🐓' ]
$ ./barnYardAnimal.js-
$ ./barnYardAnimal.js-  return barnYardAnimals.includes(animal)
$ ./barnYardAnimal.js-}
--
$ ./trees.js:function isTree(tree) {
$ ./trees.js-  const trees = [ '🌲', '🌳', '🌴', '🎄', '🎋' ]
$ ./trees.js-
$ ./trees.js-  return trees.includes(tree)
$ ./trees.js-}
--
$ ./leaves.js:function isLeaf(leaf) {
$ ./leaves.js-  const leaves = [ '🍁', '🍂', '🍃' ]
$ ./leaves.js-
$ ./leaves.js-  return leaves.includes(leaf);
$ ./leaves.js-}

Wrapping Up

The above are a cursory overview of a few common $ grep uses. The command has many more -> check them all out by running $ man grep.