Command line snippets

The fine art of snippet curation

I’d like to share with you some details about a command line interface (CLI) tool that I enjoy using to curate my collection of complex and seldom used but powerful CLI snippets and one-liners.

This article is for folks who enjoy using the CLI, and for those who would also like to learn about an approach for curating and using a personal collection of command line snippets.

CLI snippets and one-liners act like magic spells, and you might find it difficult to recall the most complex of them. For example, when you need to extract the files from a Debian Linux .deb package on a BSD style system, but who can easily recall a command like ar:

ar vx <package_name.deb>

or how about showing the number of connections in use by PID for a process with strace?

strace -p $(pidof <process_name>) \
  -f \
  -e trace=network \
  -s 10000

How do I add an Internet password to the macOS Keychain from the command line again? Oh, yeah:

security -v add-internet-password \
  -a <account> \
  -s <server> \
  -w <password>

All the handy snippets a regular user of the command line cannot fit in their mind need another home; for some, this is often a text file. How about the idea of using a text file that brings useful per-snippet attributes and works with a neat CLI tool for managing and searching them?

Some people have success with the built-in snippet capabilities of their preferred text editor. Having never really tried my editor’s own snippet system, I wanted a more universal tool where the snippets had more usefulness both in and outside of the text editor environment as well.

In the beginning, I used a GitHub gist to stash my snippets. Then eventually, I moved to a git repository of Markdown documents represented a carefully cataloged snippet collection. This proved difficult to search and keep synchronized between systems.

Say hello to pet

I like to use pet by Teppei Fukuda to manage my snippets now. pet is a fantastic and focused MIT-licensed, Go-based CLI tool that interfaces with a listing of CLI snippets that you keep in a TOML formatted text file.

After using pet for about a year, I’ve found it to be a minimal, but powerful approach to recalling and using snippets.

After you install the pet binary, you can use it in number of handy ways, like listing your snippets:

pet list
Description: Mirror a website with assets from various CDN servers
    Command: wget --mirror –w 2 –p –-convert-links –P -Dstatic.example.com,static1.example.com,media.example.com,cdn.example.com -H ./target_dir http://www.example.com/
        Tag: wget
------------------------------
Description: Find all non-ASCII characters in a file
    Command: [^\x00-\x7F]
        Tag: regex text
------------------------------
Description: Take a stack of items (with newlines) and make them a space separated list
    Command: echo $VALUES tr "\n" " "
        Tag: conversion text
------------------------------
Description: Create ISO-8601 dates
    Command: date +"%Y-%m-%dT%H:%M:%SZ"
...snip..

The output shows the complete raw TOML of your snippet collection.

As your snippet collection grows, you can use pet search to quickly find them:

pet search
[Use OpenSSL to generate a 32 character Base64 string. Note that this string is NOT URL safe!]: openssl rand -base64 32
[Use vegeta to test Vault generic secret retrieval at rate of R per second for S seconds]: echo "GET $VAULT_ADDR/v1/secr
[Dump an existing SQLite database file into a new file to correct for issues with indexes/mild corruption]: sqlite3 <exi
[Use Silver Searcher to show debug messages emitted by HashiCorp tools like Vault]: ag logger.Debug | ag -v vendor | les
[Run a CentOS based container with netcat installed]: docker run -t centos yum -y install nc #docker
[List processes holding handles to deleted files]: sudo lsof +L1 #lsof #sudo
[Top ten direcctories using most disk]: du -hsx * | sort -rh | head -10 #du #usage
[Extract RPM with cpio]: rpm2cpio file.rpm | cpio -i -d #linux #rpm
[Extract .deb files in BSDish Systems (including macOS)]: ar vx <filename> #bsd #deb #package
[Create ISO-8601 dates (alternate)]: date -u +%Y-%m-%dT%H:%M:%S%z #date
[Create ISO-8601 dates]: date +"%Y-%m-%dT%H:%M:%SZ" #date
[Take a stack of items (with newlines) and make them a space separated list]: echo $VALUES tr "\n" " " #conversion #text
[Find all non-ASCII characters in a file]: [^\x00-\x7F] #regex #text
[Mirror a website with assets from various CDN servers]: wget --mirror –w 2 –p –-convert-links –P -Dstatic.example.com,s
🐶 pet>                                                                                           IgnoreCase [128 (1/3)]

You can also tag snippets with # and search for tagged snippets by tag.

You can pass the search result/composed command to a clipboard wrangling tool like pbcopy on macOS:

pet search | pbcopy

and have the command ready to use with a ⌘+v.

For Linux, you can do the same with xclip or xsel.

pet search | xclip -selection clipboard

One of the nice things about the snippet format is that you can use dynamic argument placeholders for example values and pet will prompt you for the actual values, which it will then insert into the composed command line.

In practice, the UI prompting appears as shown in the following screenshot, which contains 3 arguments: a filename, a source string value, and a replacement string value.

A screenshot showing an example of dynamic arguments in pet

pet outputs a nicely composed and ready to use command line, like this:

find ./ -name test-file.txt -exec sed -i '' -e 's/sashimi/nigiri/g' {} \;

The tool feels simple and elegant in its usage while performing well.

You can use other pet commands to add new entries like pet new, or edit the existing snippets with pet edit, which invokes the editor you specify in the configuration file.

You can also use pet sync to synchronize your snippet collection to a GitHub gist or to GitLab so that you can use them in all your environments.

pet sync
Upload success

Check out the pet README for full documentation and usage examples!

hashipets

As an example snippet collection, I created hashipets, a curated collection of helpful snippets specifically for HashiCorp command line tools like Vault, Consul, Nomad, Packer, Vagrant, and Terraform.

Based on the accompanying README from the hashipets project, I’ll show how you can use them with pet and peco. Those steps work on a Mac, but I will show the process for Debian or Ubuntu Linux here instead.

Install pet

You can install pet for Linux by downloading a binary release from the GitHub project.

Visit the pet GitHub project, and download the correct .deb for your OS and distribution from the releases page.

For example, let’s use pet_1.0.1_linux_amd64.deb:

curl -O https://github.com/knqyf263/pet/releases/download/v1.0.1/pet_1.0.1_linux_amd64.deb

Install the package.

dpkg -i pet_1.0.1_linux_amd64.deb

Check the version.

pet version
pet version 1.0.1

Nice. Now you have pet installed. You just need a choose a selector, write some configuration, and add your snippets to get up and running.

Choose a fuzzy finder selector

Now you need to pick a fuzzy finder selector for use by pet to enable convenience features like searching.

While you can use any selector you like, pet automatically supports two of the most common selectors:

The hashipets project example uses peco, so this guide will too. Feel free to try fzf if you prefer; both can get the job done.

Install peco

You can install peco by downloading a binary release from the GitHub project.

Visit https://github.com/peco/peco/releases, and download the correct .tar.gz for your OS and distribution.

In this example, I use peco_linux_amd64.tar.gz from the 0.5.11 release tag.

Untar the archive:

tar  -zxf peco_linux_amd64.tar.gz

Copy the binary to /usr/local/bin:

sudo cp peco_linux_amd64/peco /usr/local/bin/

Check the installation by getting the version:

peco --version
peco version v0.5.11 (built with go1.20.2)

Now you can configure pet and peco to wok together.

Configure pet to use hashipets snippets

In this example, I clone the hashipets repository to a temporary directory, then configure pet to use its snippets.

Define the hashipets snippets temporary directory:

export HASHIPETS=/tmp/hashipets

Clone the hashipets repository into the temporary directory:

git clone https://github.com/brianshumate/hashipets.git $HASHIPETS

Configure pet to use the hashipets snippets:

pet configure

Use the value from $HASHIPETS to create the full path for the snippetfile option value: /tmp/hashipets/hashipets.toml.

Review this complete pet configuration example from ~/.config/pet/config.toml:

[General]
  snippetfile = "/tmp/hashipets/hashipets.toml"
  editor = "vim"
  column = 40
  selectcmd = "peco --layout=bottom-up"

[Gist]
  file_name = "my-custom-snippets.toml"
  access_token = "42c0ffee8ddc568ffc0ffeeae8ac0ffeebe2a474"
  gist_id = "c0ffee3b76be396c0ffeede8dc0ffe73"
  public = false

Let’s break down the configuration example:

  • General pet settings
    • snippetfile: the path to our snippets
    • editor: the editor invoked with pet edit
    • column: the target display column width
    • selectcmd: the command line for the select/search tool
  • Gist settings
    • file_name: the gist filename
    • access_token: the GitHub personal access token
    • gist_id: the gist ID string
    • public: gist public visibility

Configure peco

Go ahead and set up a custom peco configuration if you’d like as well; this example from hashipets makes for a fun inspiration:

mkdir -p ~/.config/peco &&
  tee ~/.config/peco/config.json <<EOF
{
    "Prompt": "🐶  pet>",
    "Style": {
        "Basic": ["on_default", "default"],
        "SavedSelection": ["bold", "on_yellow", "white"],
        "Selected": ["underline", "on_cyan", "black"],
        "Query": ["yellow", "bold"],
        "Matched": ["white", "bold"]
    }
}
EOF

You can now try a command to get started; go ahead and search the hashipets snippets:

pet search

Provided all went well, you should can browse the snippet list and search or filter your snippets as in this screenshot:

Screenshot showing browsing of hashipets snippets in pet

I hope find some use in this article, and the projects in it!