3 ms·
There’s also a lot of good design that’s gone into Elvish. And I don’t think it’s fair to call it “dead” when the maintainers for Elvish are active both on Gith
by hnlmorg 2y ago
There’s also a lot of good design that’s gone into Elvish. And I don’t think it’s fair to call it “dead” when the maintainers for Elvish are active both on Github and here on HN too (probably other places too).
However if you’re looking for an alternative then there’s:
- Murex (disclaimer: I’m one of the maintainers) which does support background processes and has extensive documentation. https://murex.rocks https://murex.rocks
- Nushell: I’m not personally a fan of its design choices but it has a large following of people who do really enjoy it so it might also appeal to yourself too.
As for Elvish, I do encourage others to give it a go themselves. It’s really well thought out and what might be a deal breaker for some people isn’t for others.
- rendaw 2y agoElvish had some very cool ideas, which is why I tried it out! Like the built in script checker! But it also has a lot of very basic issues that have been open for years, and TODOs in the documentation as I mentioned. People are going to read your message and put N hours into it and get burned, and I think this is a fair warning. Nushell also had very minimal background task support, so I rejected that. They explicitly say use some other program for background tasks in their docs. I actually looked at Murex after seeing it in previous threads, but I bounced for some reason... I just took another look though skipping the tutorial and I see you have `bg` and `fg` support! But does `bg` return the `fid`? Can you use those in scripts, or are they hobbled the same way bg/fg are in bash? It's been a good 4-5 months since I went down this rabbit hole, but IIRC the basic things I wanted to do and got blocked in multiple shells were: - System-wide interactive-use config file, I use Nixos and manage my system config using that - Background task support - I need to start an ssh tcp proxy, pipe a command over it, then kill ssh once the command is done (all in a script). - Post-command hook, to send a notification when a long command finishes - Async iteration of command output, i.e. streaming events with swaymsg subscribe and running a command when certain events occur - Value/call arity safety - i.e. a clear distinction between a single value and multiple values that doesn't rely on stringification hacks. I.e. in `command $x` `command` should always have one argument, regardless of the contents of `x`, and making that plural should be explicit. And then other standard evaluation criteria, like I looked at xonsh but it seemed like a massive hack, despite handling a lot of the above.
- hnlmorg 2y ago> does `bg` return the `fid` There's two kinds of process IDs in Murex: FID (function IDs) and PID (process IDs) Forking is expensive in POSIX and has a number of drawbacks such as the inability to share scoped variables without resorting to environmental variables. So a FID is basically a PID but managed inside the scope of Murex's runtime. You can manage FIDs in much the same way as you can manage PIDs, albeit using Murex builtins rather than coreutils (though PID management tools in Bash are technically builtins rather than coreutils too). What this means in practice is you can have entire blocks of code pushed into the background, eg » GLOBAL.name = "rendaw" » bg { sleep 5; echo "Hello $name" }; echo "not bg" not bg Hello rendaw You can see the FID as well as the job ID the usual way, via `jobs` » jobs JobID FunctionID State Background Process Parameters %1 2109 Executing true exec sleep 5 ...and you can kill that entire `bg` block too fid-kill 2109 But you'd also see any non-builtins in `ps` too: » ps aux | grep sleep hnlmorg 72749 0.0 0.0 410743712 1728 s012 S+ 4:24p.m. 0:00.00 /usr/bin/grep --color=auto sleep hnlmorg 72665 0.0 0.0 410593056 432 s012 S+ 4:23p.m. 0:00.00 /bin/sleep 5 > Can you use those in scripts, or are they hobbled the same way bg/fg are in bash? While the above seems very complicated, the advantage is that `bg` and `fg` become much more script friendly. > - System-wide config file, I use Nixos and manage my system config using that This isn't Murex's default behaviour but you could easily alter that with environmental variables: https://murex.rocks/user-guide/profile.html#overriding-the-default-paths-xdg https://murex.rocks/user-guide/profile.html#overriding-the-d... The latest version of Murex (v7.0.x), which is due to be released in the next few days, makes this even easier with a $MUREX_CONFIG_DIR var that can be used instead of multiple specific ones. > - Background task support - I need to start an ssh tcp proxy, pipe a command over it, then kill ssh once the command is done (all in a script). Murex has another layer of support for piping in addition to those defined in POSIX, which are basically channels in the programming language sense. In murex they're called "Murex Named Pipes" but the only reason for that is that they can be used as a glue for traditional POSIX pipes too. This is one area where the documentation could use a little TLC: https://dev.murex.rocks/commands/pipe.html https://dev.murex.rocks/commands/pipe.html > - Post-command hook, to send a notification when a long command finishes There are two different events you can hook into here: - onPrompt: https://dev.murex.rocks/events/onprompt.html https://dev.murex.rocks/events/onprompt.html This is similar to Bash et al prompt hooks - onCommandCompletion: https://dev.murex.rocks/events/oncommandcompletion.html https://dev.murex.rocks/events/oncommandcompletion.html This hooks into any command name that's executed. It runs the comment in a new TTY and buffers the command's output. So, for example, if you want a command like `git` to automatically perform a task if `git push` fails with a specific error message, then you can do that with onCommandCompletion. > - Async iteration of command output, i.e. streaming events with swaymsg subscribe and running a command when certain events occur I'd need to understand this problem a little more. The channels / Murex Named Pipes above might work here. As might onCommandCompletion. > - Value/call arity safety - i.e. a clear distinction between a single value and multiple values that doesn't rely on stringification hacks. I.e. in `command $x` `command` should always have one argument, regardless of the contents of `x`, and making that plural should be explicit. This one is easy: scalars are always $ prefixed whereas arrays are @ prefixed. So take the following example: array = %[ a b c ] » echo $array ["a","b","c"] # a single parameter representation of the array » echo @array a b c # the array expanded as values ----- This is quite a lengthy post but hope it helps answer a few questions
- ghthor 2y agoThere is ysh
- em-bee 2y agocould you go into more detail how (and maybe why) murex and elvish differ? also, i'd like to know more about how the job control works. that's one of the pain points in elvish, but both are written in go, so maybe there are some ideas that elvish could copy.
- hnlmorg 2y agoMurex and Elivish share a lot of similar design goals. The author of Elvish has done a lot of great talks about his approach to Elvish development and you can tell a lot of care has gone into its design. With Murex, I initially took a "let's just experiment until I find something that works" with no fear of writing ugly proof-of-concept code. This allowed me to build a lot of stuff very quickly and originally it was written in a self-hosted git repository to solve my own problems. But as the project evolved I realised there was some good stuff in there that's worth sharing. The downside to this approach is that there is some ugliness to its design that has lasted even to the latest version due to Murex's compatibility promise. However, the latest version of Murex does provide an internally versioned runtime, which means scripts can now pin to a specific version of Murex and not worry about gradual changes over time (even if "gradual over time" in this context literally means "years of compatibility" even before the versioned runtime. This means that Murex and Elvish might feel like very different shells despite being conceptually quite similar. I'm a little reluctant to give specific areas where the two shells diverge because both are under active development and thus moving targets. So what might be true today might not be true tomorrow. However, I will say the syntax for each does vary significantly despite being superficially similar. As for job control, this was part of Murex's early design because it's a feature I used heavily at the time. So the concept of background and foreground processes are weaved throughout all of the core runtime. Like with Elvish, Murex doesn't create new UNIX processes for builtins. And with commands that are forked processes, Murex doesn't hand over complete ownership of the TTY to them so that Murex can still catch the signals. The reason for the latter is because Murex can then add additional hooks to job control, such as returning a list of open files any stopped processes have opened, and how far through reading those files it is. So Murex has needed to re-implement some of the job control logic that would normally be handled by the POSIX kernel. This does result in a lot of additional code, and thus places for things to go wrong. On balance, I think I made the right tradeoff for Murex. However if I were to write an entirely new shell from the ground up, I'd probably not do it this way again.