Sometimes it's possible to just wrap these up in scripts but often my invocations of that script get so variable that I need many flags etc and now the commandline gets really long and I'm back at square one.
A little hard to describe in the abstract so here's a present example:
- I wanna compile a kernel and boot it up in QEMU, then SSH into it.
- But sometimes, I wanna skip the build (it takes a few seconds to detect that the tree is unchanged)
- Sometimes, I wanna boot with a different special disk file.
- Sometimes, I wanna change the networking setup. Sometimes this requires me to charge the part of the commandline that SHH's into the VM, to match the changes I made to the QEMU commandline.
- etc etc
So I just have a huge command line in my shell history and I bring it up and manually edit it each time.
But I think it's possible to make this process more convenient. An inspiration for this is Magit, an Emacs plugin that allows (among many other things) building up and stringing together lots of complex git commandlines with varying flags, via a few keypresses in a discoverable text UI.
I wonder if something like this already exists? If not I think it could be a fun design challenge. By looking at the shell history and using heuristics about common CLI design patterns perhaps you could automatically create keyboard shortcuts.
Define your recipes and then you can compose them as needed.
[0] https://github.com/casey/just
I also use Just for build and deploy commands. Other thing I was thinking of was setting environment variables. Complex pipelines can be split into several dependent recipes. Or using shell aliases you can string them together yourself with regular pipes in very compact form. Just recipes defer to shell or a programming language of your choice. Just makes some shell stuff easier without replacing or hiding it.
[1] https://just.systems/man/en/chapter_68.html
Edit: I also added Atuin https://atuin.sh/ recently to better deal with shell command history. Though that one I’m still learning.
I've tried making pretty scripts with many options, but as you said, then you just end up with another tool with many complicated options, not to mention the time it takes. I noticed that the quick and dirty scripts that I often just copy paste and tweak if I want to get a different functionality get by far the most use and survive the longest.
I've also been meaning to have a look at invoke[1] which seemed interesting, but I haven't gotten to it yet.
[1] https://www.pyinvoke.org/
This is not in the style of `transient` in Emacs but it could work well, especially with your wrapper script that takes command line flags.
Note: fzf's history search feature breaks this. https://github.com/junegunn/fzf/issues/2399
Edit: And up and down will still keep the relative position you are at in your history in case you want to skip a command.
But, in truth, the shell interface could use a major overhaul to make it more like a notebook, there are early attempts at this (e.g. Warp), but it's still quite timid IMO.
I'll also say this is one of the perks of being a vi user, it's the CLI usage where it really shines, I can make surgical edits really quickly, thanks to all the jump and change keybinds that are so central to vi usage.
Silly, yes. but it's super easy and extremely fast.
If you use `exit $?` instead, you will preserve the exit status from the previous command.
Even more, I put a vim shortcut so I can run it without leaving the terminal.
Here's one for a QEMU dev env where I add and remove bits of command line in a freeform way. I just break out the command line into components, and uncomment the ones I want for a particular use:
If you have multiple stages to your build/run process, you can chain together a few scripts. build-and-run.sh builds it, and then calls run.sh which runs it. If you want to skip the build step, you use run.sh.I have a blog on doing exactly this for a subset of strace[2].
1: https://github.com/denisidoro/navi
2: https://kbknapp.dev/strace-navi/
Basically using vim as an input buffer. With the option to copy the current line- when working systems there was often incremental improvement that I was trying to do, so running then creating a new line was valuable. I probably should just learn how to insert a line offset into the current line though.
What's still missing in both my vim-driven world and in shells is any ability to make references & changes. Ideally I'd like to be able to have lines that interpolate vim registers & more complex expressions. Ideally I want a shell that lets me see my previous raw uninterpolated expressions, that hps me distil out pieces for reuse. The way that history just shows the interpolated version destroys the ability to see what & where I'm borrowing bits of the past that I could be using as hints to re-compose new futures.
0: https://pypi.org/project/questionary/
I like to tinker with bash and this has helped me keep all of the commands relevant to a particular project discoverable, accessible, and documented.
It uses a function "," for command execution. So, for instance, if the workspace file defines a function "build", when you're in the workspace, the command `$ , build` will run it.
It's not the most comprehensive solution to this, but it's probably the bit of shell programming that I use almost every day and has saved me tons of time.
[0] https://github.com/nepthar/ws.sh
The other thing I’d do is get really really good at writing shell scripts. Also nowadays it’s super easy to take an existing complex one liner and ask GPT to make it a robust script with args (but check it of course!)
I also like some of the other suggestions if you’re predisposed to them already, like Makefiles, which are simple, flexible, and powerful.
Each run generates a timestamped folder with not only the bash script, but also a copy of the configs used to generate it, and all the data that the commands in the bash script needs (json files). I find this style of generator a common pattern for commonly used but frequently tweaked scripts.
You could use a local port of something like github actions, but personally I'd pick a language (Python, TypeScript, Ruby) and make a function that takes an input kernel and optional disk and networking config, builds if the tree has changed, and returns the ssh command to the created VM.
[1] : https://unix.stackexchange.com/questions/344360/collect-exit...
snarky: get a raise via get_arrays approach works nice if billing by hour, not so much if scripting system wide scripts.[0]
[0] : https://www.linux.org/threads/init-and-its-alternatives.9279...
[0] https://www.pyinvoke.org/
https://github.com/atuinsh/atuin
For some reason it seems to try to connect to some atuin server even though I am using default config. That worries me slightly sometimes.
I also had one case where I was using ssh from my home to a machine at one of my parents place and there was an ongoing packet loss problem and so every time I press Ctrl-R to run some previous command I had to wait actual ages for the terminal to redraw because it opens atuin and shows as many lines of history as it can and also updates when you type to search. Of course that is an extreme situation, but it was wild nonetheless to see how much worse the command line experience became in those conditions because of that.
I still use it though, and will continue to as well.
2. makefiles
3. If you're using bash, try the edit-and-execute-command command. By default, this is assigned to Ctrl-x Ctrl-e (type ctrl-x, then ctrl-e).
It is a menu that works off a file that contains a collection of single line commands.
I like it because it is a local command that is only relevant to the project I’m working on, and sometimes after months of absence it is easy to pick up where I left off.
Unless you depend on the results of partial execution to decide how to execute the rest of the script, this seems like the most natural solution.
Also can recommend Justfile (it has great discoverability and it just works).
[0]: https://github.com/TekWizely/run
You can write whatever crazy nonsense you need.
I prefer Pet, mostly because Snipkit makes me verify 20 times (slight exaggerated) and doesn't give me the actual command so it'll be part of the shell history.
Honestly, just dump the command in my shell and let me press enter and make that the confirmation, but whatever.
You can give arguments with default values, so they are reusable across projects.