When I find myself repeating simple commands or pipelines in Bash I often have the instinct to write a quick function for it. (It's easy enough to repeat a command from history, but editing in filenames etc. gets irritating.)
The problem is, there's a decent chance I'll want to do the same or similar things in another terminal session in the future, and my hastily-defined functions won't persist. Writing them to my ~/.bash_aliases is too much friction, especially since I keep that file set read-only (as a tiny bit of protection against malware, which I'm told usually doesn't check). And it's not really maintainable or shareable.
So I set up a bit of automation so that I can easily save these functions permanently, as separate scripts with a shebang and everything. So not only can I use them later, I can chuck them in their own GitHub repo etc. to show off.
And then I thought, maybe others could benefit from this setup as well, so here you go. I originally wrote the main logic in Python, but converted it to Bash to remove the dependency (and to study/practice with Bash, since I really normally only use it for very simple things).
-
Put
func2cmdsomewhere writable that's on your path (I use~/.local/bin) andchmod +xit. -
(Recommended) As root, put
share-commandin/usr/local/binandchmod +xit. (This currently depends onfunc2cmdbeing in~/.local/bin.) -
(Recommended) Add this to your
~/.bashrc,~/.bash_aliasesor similar file, to simplify command-line use:make-command () { type "$1" | func2cmd && unset "$1"; }
Note that it isn't possible to replace this cleanly with a script; the script will run in an environment that doesn't contain the function being converted (unless you export -f first, which defeats the goal of simplifying use).
func2cmd example will:
- Parse the output of
type example - Ensure that the name refers to a function
- Extract the body of that function
- Save it as a Bash script in the same folder as
func2cmd
sudo share-command example will:
- Determine which user invoked
sudo - Look for
examplein that user's~/.local/bin - If found, and it wouldn't overwrite anything, copy it (using
install) to/usr/local/bin
You may find this especially useful if, like me, you use multiple local user accounts for identity management.
The etc/ folder contains a few other interesting things, which you may use or consider as you see fit:
A simple wrapper I created using func2cmd so that I can easily open other scripts created by func2cmd in Vim. Your editor, terminal etc. preferences may differ.
A utility for "dry-running" commands, to verify exactly what arguments would be passed to a command. Simply replace the command you would otherwise run with bash-cmdline; the output is a set of hex dumps of each received argument (using xxd). I've found this useful when trying to work with tricky filenames (especially those containing spaces and fancy Unicode), especially if tools like xargs are involved. It also lets you test out e.g. using Bash character expansions to supply binary data as arguments.
A wrapper, created using func2cmd, for Shantanu Jain's excellent pyp utility. It uses the --explain option, which outputs a usable Python script (complete with shebang), to add to your collection of commands. This requires a permanent installation of pyp created using either Pipx (pipx install pypyp) or uv (uv tool intall pypyp). (Note that there is a separate PyPI package named pyp; don't use that one.) The shebang for the resulting script is rewritten to use pyp's environment, so that it can use pyp-provided functionality such as pypprint.
The original version of func2cmd, written in Python.