Shell Games

Sometimes Unix pipe operator and streams and filters are the right tool for the job. This page may grow into a collection of interesting combinations.

Some dev environments make use of `.env` files for holding environment variables. I needed to get those variables into my shell. Here I use a perl command to reformat them to be `export`ed and use the `<()` incantation so `source` can treat the results like a file.

source <(perl -ne '!/^#/ && /=/ && s/^/export / && print' .env)

Kent Beck demonstrates that distribution of if statements in a code base follows a power law. article

# using a python code base... grep -R --include='*.py' 'if ' \ | perl -nle 'print $1 if /.*if (.*):/' \ | sort | uniq -c \ | sort -n -r | cut -c 1–5 \ | sort -n | uniq -c

Today I needed to remove some markup from the end of many, many files. I learned a new-to-me enhancement for a perl idiom I particularly like. `perl -pi -e 's{}{}' *.txt` allows a hacker to edit lines in many files in place. What I learned today is how to get the substitution to span multiple lines while processing many files. Specifically `-0777` is a perl convention which tells perl to slurp in whole files, instead of operating one line at-a-time.

perl -0777pi -e 's{\s<div class="section comments"><a name="comments"></a>\s+</div>\s+\z}{}' *.html

.

I have a small collection of test pages I use when developing plugins for federated wiki. Sometimes I need to be able to edit the pages and perform admin-only operations. Here's a trick for launching a local server. We'll explain the incantations below.

node index.js --data ./.data \ --security_type=friends \ --admin \ $(jq -r .friend.secret .data/status/owner.json \ | tee -a /dev/fd/2)

The .data folder holds the test pages. Wiki's friends security plugin saves the owner's name and password in the file status/owner.json

The sub-shell $(jq -r ...) is pulling the secret from that file so we can use that for the value of the --admin flag. Doing the shell incantation this way keeps the password from showing up in my ~/.history file.

But it happens that I also don't remember this password. So I want to see the password. This is where the tee command comes in. Normally tee sends STDIN to both STDOUT and to the specified file. In this case I choose a special file available in MacOS that acts as STDERR: /dev/fd/2. If I were in a linux box or inside a docker container, I could do the same trick with ... | tee -a /proc/self/fd/2

.

Today I needed to calculate a date from an email message. The email body indicated that I needed to take another action, but also needed to wait 48 hours before taking that action. Here I save an example of the command line incantation for that date math.

MacOS (and other flavors of BSD):

date -j -v+48H 01151950

GNU date:

date --date="2026-01-15T19:50-0700 + 48 hours"

.

See other tricks with POSIX shells at heredoc Shell Quotes.