/posts/til/til-codeturning-clipboard-sql-into-a-self-healing-mycli-workflow

Turning Clipboard SQL into a Self-Healing mycli Workflow

When Clipboard SQL Bit Me Twice Running SQL straight from the clipboard into feels great—until the query blows up and your one-shot stdin stream is gone, along with any easy way...

4 min

When Clipboard SQL Bit Me Twice

Running SQL straight from the clipboard into mycli feels great—until the query blows up and your one-shot stdin stream is gone, along with any easy way to re-run or tweak exactly what just failed. This pattern gives you the speed of piping from pbpaste when things work and, only when they don’t, automatically preserves the exact clipboard contents in a temp file and re-runs mycli against it. It turns a fragile, ephemeral workflow into one you can reliably debug and replay without changing your muscle memory.

Clipboard to Database, With a Safety Net

The core idea is to treat your clipboard as a scratchpad for SQL, then wire it straight into mycli with a single keystroke. The first leg, pbpaste | mycli -f /dev/stdin, says: “take whatever is in the macOS clipboard, pipe it into mycli, and pretend that stream is a file.” mycli thinks it’s reading from a filename, but /dev/stdin is just a special path that resolves to the current process’s standard input.

The second leg is the safety net: || pbpaste > /tmp/clip.29666 && mycli -f /tmp/clip.29666. The || only runs if the first mycli invocation exits non‑zero (for example, because your SQL has a syntax error and mycli bails before consuming stdin cleanly). In that case, you immediately dump the same clipboard contents into a real file under /tmp, then run mycli again pointing at that file. Now mycli is reading from a regular file descriptor, which is much less fragile than a one‑shot stdin stream.

The trade‑off is between ephemeral convenience and stable re-runs. Piping from pbpaste into /dev/stdin is fast and leaves no trace, but once that stream is consumed or the process errors out mid‑read, you can’t easily re‑invoke the same input. Writing to /tmp adds a tiny bit of I/O and filesystem clutter, but in return you get a durable artifact you can re-run, edit, diff, or feed into other tools. The pattern chains these behaviors so you get the ephemeral path when it works and the durable path only when you need it.

The subtlety is that the shell’s exit codes and operator precedence are doing most of the orchestration. pbpaste almost always exits 0, so the success or failure of the first leg is effectively “did mycli like this input?” If it didn’t, the fallback both preserves the exact clipboard snapshot and switches mycli into a mode where it can be re-run reliably. Once you see it that way, this isn’t just a cute one‑liner; it’s a reusable pattern for turning any fragile stdin‑based workflow into a self‑healing, file‑backed one.

💡 Did you know: On macOS, /dev/stdin is just a symlink into /dev/fd, which is why many tools that expect a filename will happily accept it as a pseudo-file pointing at standard input.

Watching the Fallback Kick In

# 1. Put a broken SQL statement in your clipboard
pbcopy <<'SQL'
SELEC * FRM users;  -- intentionally broken
SQL

# 2. Run the pattern
pbpaste | mycli -f /dev/stdin \
  || pbpaste > /tmp/clip.$$.sql && mycli -f /tmp/clip.$$.sql

# What happens:
# - mycli reads from /dev/stdin, hits a syntax error, and exits non-zero
# - Because of the non-zero exit, the right side of `||` runs
# - The same clipboard contents are saved to /tmp/clip.<pid>.sql
# - mycli is invoked again, this time reading from the saved file
# - You can now re-run or edit /tmp/clip.<pid>.sql as needed

# 3. Afterward, you can inspect or tweak the exact query that failed
sed -n '1,5p' /tmp/clip.$$.sql

If you fix the SQL so it’s valid and re-run the same command, the first mycli succeeds and the || ... && mycli -f /tmp/... branch never fires, so no temp file is created.

The Insight

You can make clipboard‑driven commands self‑healing by piping into /dev/stdin on success but automatically snapshotting the same input to a temp file and re‑running when the first attempt fails.

🧠 Bonus: You can swap pbpaste/pbcopy for xclip or wl-copy/wl-paste on Linux and keep the exact same shell pattern, turning it into a portable ‘clipboard to tool’ bridge.

Gotchas

  • Operator precedence trap → || binds tighter than && in many shells, so a || b && c is parsed as a || (b && c), not (a || b) && c. If you intend the latter, you must add parentheses or you’ll run commands in the wrong situations.
  • Clipboard emptiness vs. command failure → pbpaste exits successfully even when the clipboard is empty, so this pattern only falls back when mycli fails, not when there’s “no data”. That’s fine for syntax errors, but not for detecting an empty clipboard.
  • Temporary file reuse → Hard-coding a temp filename like /tmp/clip.29666 risks collisions between terminals or users. If two shells share that path, you can end up running mycli against the wrong person’s clipboard contents.
  • Tool-specific stdin quirks → Some CLI clients treat -f /dev/stdin differently from -f - or plain stdin, so this exact pattern may not port cleanly to other tools without checking how they detect ‘reading from a file’ vs ‘reading from stdin’.

Takeaways

  • Use /dev/stdin to trick filename-only tools into reading from a pipe when everything goes well.
  • Wrap fragile stdin workflows in cmd1 || save_input && cmd2 to automatically capture failing inputs into a file for re-runs.
  • Parameterize the temp path with $$ or mktemp so each shell session gets its own safe scratch file.
  • Remember that in a || b && c, && binds tighter; add parentheses if you need (a || b) && c instead.
  • Generalize this pattern to other tools (linters, formatters, compilers) whenever you’re piping from the clipboard or an editor and want automatic repro artifacts on failure.

🔥 One more thing: Many CLI tools that claim to only accept filenames actually read via fopen under the hood, which means any path that resolves to a readable file descriptor (like /dev/stdin) usually works even if it’s not documented.

References