4 ms·
You can also turn a Bash function into a script command with almost no effort, such as making a file called "run" and putting this in it: #!/usr/bin/env ba
by nickjj 5y ago
You can also turn a Bash function into a script command with almost no effort, such as making a file called "run" and putting this in it:
#!/usr/bin/env bash
set -eo pipefail
function hey {
echo "Hey!"
}
TIMEFORMAT=$'\nTask completed in %3lR'
time "${@}"
Now after running a `chmod +x hey` can run it with: ./run hey
Feel free to replace "time" with "eval" too if you don't want your command timed.
This is a really useful pattern because it means you can create a "run" script with a bunch of sub-commands (private or public), auto-render help menus and create project specific scripts without any boilerplate. Bash also supports having function names with ":" in the name so you can namespace your commands like "./run lint:docker" or "./run lint:frontend".
I have a practical example of this sort of thing here: https://github.com/nickjj/docker-flask-example/blob/main/run https://github.com/nickjj/docker-flask-example/blob/main/run
I've written about this pattern in more detail here https://nickjanetakis.com/blog/replacing-make-with-a-shell-script-for-running-your-projects-tasks https://nickjanetakis.com/blog/replacing-make-with-a-shell-s.... It's basically a less limited Makefile for when you want to make project specific aliases. This is something I use all the time now.
- abbeyj 5y agoIf you don't want the timing, use `"${@}"`, not `eval "${@}"`. The latter will parse all of your arguments through the shell an additional, unwanted time. For example, take the command `./run echo "Don't"`. When using `time`, this will print `Don't`. If you use just `"${@}"`, it will also print `Don't`. But if you use `eval "$@"`, this will crash with an error like eval: line 10: unexpected EOF while looking for matching `''
- francislavoie 5y agoI do the same thing, but slightly differently. https://github.com/francislavoie/laravel-websockets-example/blob/main/docker/utils https://github.com/francislavoie/laravel-websockets-example/...
- quotemstr 5y agoOne of my biggest pet peeves is people defining commands and utilities as shell functions and demanding I source some environment setup script instead of just making regular command scripts and running them as normal programs. My shell is my computing environment. It's rude for a script author to make me change my computing environment when he could just as easily have made a script and created his own sandboxed environment that wouldn't interfere with mine. People should never ship end user interfaces as bundles of shell functions that have to be sourced. (I'm looking at you, Android build system.)
- earthboundkid 5y agoI remember when I first interacted with Ruby Gems and learned I needed to source some file to make it work, I thought, "Wow, Ruby is so weird and magical they can't even use the shell normally." The joke was on me when Python virtual envs became a thing.
- anitil 5y agoOne thing I like about make is that you get an automated bash completion for targets, which I find helpful. Is there an equivalent sneakiness for doing this with this style of script?
- nickjj 5y agoI have not found a way to do that, but other Bash driven CLI tools do offer completion. It might come down to having to define a separate completion file. Something like this: https://askubuntu.com/questions/68175/how-to-create-script-with-auto-complete https://askubuntu.com/questions/68175/how-to-create-script-w... If you check the first link in my previous reply it does include an auto-generated help menu that uses compgen to print a list of functions near the bottom. This way you can run `./run` or `./run help` to get a list of commands. I find this is helpful enough without needing completion, especially since every function ends up being a top level command.
- anitil 5y agoAh yes I did see the compgen bit, and promptly stole it for all my scripts
- wruza 5y agochmod +x hey Did you mean chmod +x run?
- nickjj 5y agoOops yeah, good catch!
- earthboundkid 5y agoI learn about this technique reading @chubot, and now I use it all the time.