Fredrb's Blog

Bash one liners

I have a graveyard of one-time-use bash one-liners that become either aliases or get wrapped by shell functions in my .zshrc file. I often justify the effort of polishing them and adding to my dotfiles with the excuse that they will be used again in the future. Even if they are never used again, they serve as a library of examples. For every new command, there is always an old one that did a similar thing.

More importantly, these bash one-liners are really fun to write. What once started as a thought to build a new command line application, was first challenged with a “could it be a simple bash script?” and then finally it was reduced to “could I write it one line?”. It’s like my own personal code golf challenge, where I keep trying to make the line smaller and smaller.

There is also something magical about slowly incrementing your program in a REPL, and piecing the commands individually until I understand how to plug them together in my one-liner. The feedback loop is so satisfyingly quick. You start with a simple command that just parses a list and spits it back to the terminal and then iterate on it. Refining and expanding it one command at a time.


Unmaintained go.mod dependencies

Today I had an itch I had an urge to scratch scratch: to figure out how many of the dependencies in a go.mod file were repositories that are likely no longer maintained and how many stars they had.

This is the magic one-liner:

for repo in $(cat ./go.mod | grep "\tgithub.com/" | sed 's/\t//' | sed 's/\ v.*//' | sed 's|github\.com/\([^/]*\/[^/]*\).*|\1|p' | uniq); do; printf "Last commit: %10s | %5s ⭐ | %s\n" "$(gh api /repos/$repo/commits | jq -r '.[0].commit.author.date' | sed 's/\(.*\)T.*/\1/')" "$(gh api /repos/$repo -q '.stargazers_count')" "github.com/$repo"; done;

Important to note: this command uses GitHub’s command line application gh. If you are running this yourself, make sure to authenticate with gh auth.

Results on gohugoio/hugo’s go.mod file


Command breakdown:


Maybe next time I’ll record the process of writing the command itself. I’m guessing it would be valuable to look in hindsight the increments made. With this one, they appeared roughly in this order:

  1. Extracting the list of GitHub dependencies from go.mod
  2. Clean the lines and strip unwanted prefixes and suffixes
  3. Passing the URL to gh api repo/OWNER/REPO/commits
  4. Discovering I needed to extract only the OWNER/REPO from the URL and that some dependencies had additional suffixes.
  5. Battling with the strings until I got a regex that extracted only the part I wanted
  6. Wrapping the command in a for loop to make it easier to parameterize the repo name
  7. Add jq command to extract commit date and stargazers
  8. Format strings

⇦ Back Home | ⇧ Top |

If you hated this post, and can't keep it to yourself, consider sending me an e-mail at fred.rbittencourt@gmail.com or complain with me at Twitter X @derfrb. I'm also occasionally responsive to positive comments.