[HN Gopher] Elvish - Scripting language and interactive shell
       ___________________________________________________________________
        
       Elvish - Scripting language and interactive shell
        
       Author : kartikarti
       Score  : 73 points
       Date   : 2025-04-30 11:51 UTC (4 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | baobun wrote:
       | Anyone here using elvish on the regular? Anecdotes please!
        
         | sidkshatriya wrote:
         | I don't use Elvish daily (I use fish) but writing scripts in
         | Elvish is a great experience. The elvish executable can serve
         | as an LSP server and that makes writing Elvish scripts a bit
         | easier.
         | 
         | I don't care much for the Elvish shell experience, rather I
         | like the Elvish scripting language. The documentation is top
         | notch and the language evolves slowly and feels stable.
        
           | einpoklum wrote:
           | > I don't care much for the Elvish shell experience, rather I
           | like the Elvish scripting language.
           | 
           | It's a shell, aren't those two things supposed to be the same
           | basically? Or - do you mean the interaction with the
           | terminal/command-line?
        
             | sidkshatriya wrote:
             | The shell prompt is also a small interface. How your shell
             | responds to tab autocomplete, provides suggestions etc. can
             | be quite helpful. Here I just like the way fish suggests
             | filenames, provides an underline for filenames that exist
             | and so on.
             | 
             | The language is what you write in an $EDITOR. Here Elvish
             | scripts can be nice, succinct and powerful. I like how I
             | don't have to worry about strange "bashisms" like argument
             | quoting etc. Everything feels consistent.
        
       | IshKebab wrote:
       | Looks nice. Obviously way better than Bash, but there are a few
       | options that are way better than Bash, so I feel like it should
       | spend some time convincing me why I should use this over e.g.
       | Nushell.
       | 
       | Anyone have any experience of both?
        
         | sidkshatriya wrote:
         | nushell vs Elvish
         | 
         | The Nushell and Elvish scripting languages are similar in many
         | ways. I personally find the "shell" experience better in
         | Nushell than Elvish.
         | 
         | Nushell
         | 
         | - Bigger community and more contributors
         | 
         | - Bigger feature set than Elvish
         | 
         | - Built in Rust (Yay :-)! )
         | 
         | Elvish
         | 
         | - Mostly developed by one person
         | 
         | - Built in golang
         | 
         | - Amazing documentation and general attention to detail
         | 
         | - Less features than Nushell
         | 
         | - Feels more stable, polished, complete than Nushell. Your
         | script written today more likely to work unaltered in Elvish a
         | year down the line. However this is an impression. Nushell must
         | have settled down since I last looked at it.
         | 
         | For "one off" scripts I prefer Elvish.
         | 
         | I would recommend both projects. They are excellent. Elvish
         | feels less ambitious which is precisely why I like it to write
         | scripts. It does fewer things and I think does them better.
         | 
         | Nushell feels like what a future scripting language and shell
         | might be. It feels more futuristic than Elvish. But as
         | mentioned earlier both languages have a lot of similarities.
        
           | graemep wrote:
           | > Built in Rust
           | 
           | > Built in golang
           | 
           | Does that matter?
           | 
           | If you intend to be a contributor, of course the chosen
           | language matters, but only a very small proportion of users
           | will be contributors.
        
             | dijit wrote:
             | There are quirks specific to languages.
             | 
             | Rust _tends_ to be marginally faster and compile to smaller
             | binaries.
             | 
             | Go projects tend to hit maturity faster and develop
             | quicker.
             | 
             | Its a relevant factor to quickly stereotype certain
             | characteristics of development, but its not anywhere close
             | to important.
        
             | IshKebab wrote:
             | I don't think it matters whether it's Rust or Go
             | especially, for an end user tool. But it definitely matters
             | if it's Rust/Go compared to something else like C or
             | Python.
             | 
             | The language choice has certain implications and I would
             | say Rust & Go have fairly similar implications: it's going
             | to be pretty fast and robust, and it'll have a static
             | binary that makes it easy to install. Implications for
             | other languages:
             | 
             | C: probably going to have to compile this from source using
             | some janky autotools bullshit. It'll be fast but segfault
             | if you look at it funny.
             | 
             | Python: probably very slow and fragile, a nightmare to
             | install (less bad since UV exists I guess), and there's a
             | good chance it's My First Project and consequently not well
             | designed.
        
               | graemep wrote:
               | Not even that matters to me: I will install from repos.
               | It might make packagers' lives a bit more difficult in
               | some cases but they are probably very familiar with that.
               | 
               | I have not really had problems with installing C (on the
               | rare occasions I have compiled anything of any
               | complexity) nor Python applications. Xonsh is supposed to
               | be pretty good and written in Python, and most existing
               | shells (bash, zsh, csh etc.) are written in C.
               | 
               | Amusing aside, I use fish and until I decided to fact
               | check before adding it to the list of shells written in
               | C, I did not realise it was written in Rust.
        
               | IshKebab wrote:
               | Fish switched from C++ to Rust really recently.
               | 
               | https://fishshell.com/blog/rustport/
        
               | graemep wrote:
               | That is impressive.
               | 
               | Now you mention it I vaguely recall reading something
               | about it somewhere as planned but its been done!
        
         | Levitating wrote:
         | What about fish? I've enjoyed using it for years.
         | 
         | There's a few obvious features missing in fish like
         | backgrounding an alias or an equivalent to set -e, other than
         | that I have no complaints.
         | 
         | The first thing I do on any machine is install fish.
        
           | sidkshatriya wrote:
           | fish is amazing. I use it as my primary shell.
           | 
           | But for writing scripts I would reach for Elvish/Nushell.
           | More powerful.
        
       | atiq-ca wrote:
       | Looks interesting! Does it have OOP features kinda like how
       | powershell has that?
        
       | photonthug wrote:
       | While removing weird stuff from daily bash annoyances is
       | interesting, I'm not necessarily looking to replace that with
       | brand new but also pretty random weird stuff. Adding new rules
       | isn't the same as adding structure. The documentation is also
       | frequently strange in a way that makes it hard to digest. From
       | https://elv.sh/learn/first-commands.html#external-commands
       | 
       | > While Elvish provides a lot of useful functionalities as
       | builtin commands, it can't do everything. This is where external
       | commands come in, which are separate programs installed on your
       | machine. Many useful programs come in the form of external
       | commands, and there is no limit on what they can do. Here are
       | just a few examples: Git provides the git command to manage code
       | repositories
       | 
       | At first I thought, wait, is this a shell or not, do I have to
       | write code or something to get access to normal external
       | commands? But no, this is more like going to a car dealership and
       | having the salesman say "Hey thanks for coming by, a car is a
       | mechanical device consisting of metal parts and rubber parts for
       | the purpose of taking you where you need to go! Now that we're on
       | the same page about that, money is a thing made of paper for the
       | purposes of .."
       | 
       | Docs are hard, once or twice is fine, but lots of parts are like
       | this and I gave up reading. Not sure if it's AI generated, but if
       | the project is doing that then it should stop, and if it's not
       | doing that it should consider starting to
        
         | nneonneo wrote:
         | I mean, you are literally reading the first chapter of the
         | tutorial for beginners ("Beginner's Guide to Elvish is for you
         | if you haven't used shells a lot or want to brush up on the
         | basics").
         | 
         | They have a separate set of docs for people who do have some
         | experience with other shells (https://elv.sh/learn/); you may
         | find the quick tour more suitable for your speed:
         | https://elv.sh/learn/tour.html
        
           | photonthug wrote:
           | I did browse around, that's the page I got the first part of
           | my comment from. Modules are one example of something that
           | sounds probably good
           | (https://elv.sh/ref/language.html#modules ). Good stuff is
           | really weakened though by the many random changes that seem
           | to go from arbitrary to.. also arbitrary, while destroying
           | any chance of readability, backwards compatibility, or
           | interoperability. Why?
           | 
           | > Line continuation in Elvish uses ^ instead of \
           | 
           | > Bash: echo _.[ch] vs Elvish: echo_.?[set:ch]
           | 
           | One more example, guess what this does: `echo &sep=',' foo
           | bar`. Is it bash, elvish? Some combination of the two with
           | markdown? Legal in all three? Elvish certainly cleans up
           | conditionals and stuff, but you probably shouldn't introduce
           | new things with exactly the same name _unless_ you 've
           | created a genuine superset/dialect where the older version
           | still works without rewrite. Namespace it as elvish.echo or
           | use your module system. Shadows aren't friendly, this is
           | equivalent to the guy that monkey-patches
           | sys.stderr=sys.stdout to work around their one-off problem
        
             | layer8 wrote:
             | Elvish is designed for use on Windows as well, where \ is
             | the directory separator and wouldn't be uncommon to occur
             | at the end of a command line, so that can't be used for
             | line continuation. Windows (and DOS?) batch files use ^ for
             | line continuation, so that's probably where it was adopted
             | from.
        
       | rendaw wrote:
       | I went down this route based on HN recommendations, with some
       | people calling it stable well documented.
       | 
       | There's TODOs all over the documentation! There's no background
       | task tools for scripting, and in interactive use background tasks
       | are barely supported - an issue about background tasks has people
       | going roughly "nobody needs to do tasks in parallel, that was
       | only important when people were working on mainframes". The shell
       | hooks have (undocumented) weird restrictions. Lazy iteration of
       | lists is only supported by using functions with callbacks. Stable
       | = development appears stopped.
       | 
       | This is half baked and dead. For my new computer I really
       | _really_ wanted a lightweight new shell with orthogonal syntax
       | thought out from the ground up and not glued together over 4
       | decades, and this seemed like the closest option! But this isn 't
       | it.
        
         | nerdponx wrote:
         | The big one for me is no string interpolation, as a deliberate
         | design choice.
        
           | em-bee wrote:
           | what can string interpolation do that i can't also do by
           | sandwiching a variable between strings:
           | 'string1'$var'string2'?
           | 
           | string interpolation is useful where concatenating strings
           | requires an operator, but i don't see the benefit otherwise.
           | 
           | for more complex examples i can use printf, or someone could
           | write a function that does string interpolation. since there
           | is no need to fork, that should not be that expensive
        
             | layer8 wrote:
             | I mostly agree, but in Bash for example
             | "string1${var}string2" guarantees to be a single argument,
             | which 'string1'$var'string2' doesn't (when $var contains
             | whitespace). So it entails certain other language design
             | choices.
        
               | em-bee wrote:
               | in bash yes, so that makes sense. thanks for pointing
               | that out. in elvish $var is guaranteed to remain one
               | string, and so 'string1'$var'string2' is always going to
               | remain one argument too.
        
         | onli wrote:
         | Oil shell (now oils) was too close to bash for your goal?
        
           | rendaw wrote:
           | I think I didn't look at it initially because it was too
           | close to bash, and then by the time I burned out on fully
           | reimagined shells I fell back to zsh which was the shell I
           | knew supported post-command hooks. Definitely not a final
           | decision, but it might be a while before I try new shells
           | again...
        
           | chubot wrote:
           | FWIW Oils has two modes, and I wrote new landing pages for
           | them recently:
           | 
           |  _Nine Reasons to Use OSH_ - https://oils.pub/osh.html - it
           | runs existing shell scripts, ...
           | 
           |  _What is YSH?_ - https://oils.pub/ysh.html - It's the
           | ultimate glue language, like shell + Python + JSON + YAML,
           | seamlessly put together
        
         | rahen wrote:
         | If by any chance you're an Emacs user, check out Eshell. It
         | blends Elisp macros with shell commands, and since it keeps the
         | buffer model, you can use all the usual Emacs tools for
         | searching, sorting, and more. It's a unique shell with some
         | learning curve, but it's mature and powerful.
         | 
         | https://www.youtube.com/watch?v=9xLeqwl_7n0
        
         | hnlmorg wrote:
         | 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
         | 
         | - 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 wrote:
           | Elvish 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 wrote:
             | > 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-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
             | 
             | > - 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
             | 
             | This is similar to Bash et al prompt hooks
             | 
             | - onCommandCompletion:
             | 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 wrote:
           | There is ysh
        
         | rendaw wrote:
         | Arrg, s/lazy/async/.
         | 
         | Just to add some further qualification, I was fully prepared to
         | learn something from the ground up, throw away all my
         | preconceptions, and give some weirdness a try - including no
         | string interpolation. I wanted to 100% replace bash, both as a
         | shell and for scripting everywhere. I was exactly Elvish's
         | target user.
        
         | em-bee wrote:
         | it's still under development, but it most certainly isn't dead.
         | it's stable in that development is not disruptive. i use it as
         | a daily driver.
         | 
         | you are right about lack of support for job control, it's
         | annoying. but my understanding is that the problem seems to be
         | a difficulty in implementing job control with go. when people
         | say nobody needs parallel tasks that doesn't make sense because
         | you can run jobs in the background. you just have to do it
         | explicitly before starting, and you can't switch back and
         | forth. yes, that's a problem, and for me it is one of the most
         | annoying missing features. but it comes up seldom enough that
         | it doesn't disrupt daily use for me. which is to show that the
         | things i need for daily use are all there.
        
       | account-5 wrote:
       | Ever since I 'discovered' Nushell I've noticed a lot of new
       | shells appearing on HN.
       | 
       | The thing I like about Nushell is it does away with some of the
       | things that I found hard with bash, and made data formats a first
       | class citizen (something I enjoyed about powershell).
       | 
       | I think if you like Lisp elvish would be ideal but for me the
       | lack (seeming, I've not done a deep dive on the docs) of built-in
       | data parsing is a no.
        
         | srott wrote:
         | Elvish was a bit slow to me, nush is nice but I found out I can
         | do most of the tasks using yq and jc more intuitively.
        
       | linsomniac wrote:
       | I've been eyeing a "better shell" for a while, but I've just
       | decided that a couple zsh plugins and I'm probably happiest. As
       | the meme says "Change my mind".
       | 
       | I've been using fish for the last year or more, and I like some
       | of the "batteries included", particularly the predicting of the
       | command you want to run. But fish is too much like bash in
       | syntax, meaning that I just think of it like bash until I have to
       | type "(foo)" instead of "$(foo)", or "end" instead of "fi". The
       | zsh plugins for doing command predicting and fancy prompt seems
       | to get me all the fish benefits with none of the rough spots.
       | And, frankly, the changes fish does doesn't seem to have any
       | benefit (what is the benefit of "end" over "fi").
       | 
       | Even xonsh (I'm a huge Python fan) doesn't really have enough
       | pull for me to stick in it. Oils, nu, elvish, they all have some
       | benefits for scripting, but I can't see myself switching to them
       | for interactive use.
       | 
       | It's kind of feeling like zsh is "good enough" with no real
       | downsides. Maybe this is mostly that I've been using
       | sh/ksh/bash/zsh for 40 years, some of these other shells might be
       | easier to switch to if you lack the muscle memory?
        
         | 3PS wrote:
         | > But fish is too much like bash in syntax, meaning that I just
         | think of it like bash until I have to type "(foo)" instead of
         | "$(foo)", or "end" instead of "fi"
         | 
         | Note that fish does also support bash's "$(foo)" syntax and has
         | for a few years now.
        
           | linsomniac wrote:
           | Ooh, good to know!
        
           | em-bee wrote:
           | supporting more and more bashisms is what makes fish less
           | attractive for me. i used fish for years. $(foo) in bash
           | forks a subshell. in fish it doesn't. i am not a fan of
           | supporting different syntaxes to do the same thing. if they
           | had implemented $() to fork a subshell, that might have made
           | some sense, but otherwise it is just redundant. learning to
           | use () instead of $() or `` really isn't hard. so why?
        
         | tasuki wrote:
         | What plugins? And where is your zsh config?
         | 
         | (Ftr, I've been using zsh for maybe 5-8 years, managed to avoid
         | oh-my-zsh, and only use 'zsh-autosuggestions' and 'zsh-syntax-
         | highlighting' plugins. I've customised a theme to suit me, but
         | barely know anything about zsh to be honest...)
        
           | linsomniac wrote:
           | Well, pretty much what you said: syntax-highlighting, oh-my-
           | zsh, git, command-not-found, autosuggestions, atuin, zoxide,
           | and zsh-vi-mode. These days, I'm looking for as little stuff
           | that I have to maintain myself as possible.
        
       | Arcuru wrote:
       | I've been using fish for many years now though I keep trying all
       | these new shells.
       | 
       | Ultimately I've found that for my interactive shell I just want
       | something widely supported and with easy syntax for `if` and
       | `for` loops for short multi-line commands. For anything longer
       | than that I just reach for real Python using either the `sh` or
       | `plumbum` package.
       | 
       | I don't need the extra features very often, so I just run things
       | in full Python where I'm already comfortable.
       | 
       | I've tried oils/ysh, elvish, xonsh, nushell, and while they are
       | _fine_ I don't want to learn a different language that's not
       | quite Python and not quite shell.
        
       | dang wrote:
       | Related. Others?
       | 
       |  _Elvish, expressive programming language and a versatile
       | interactive shell_ -
       | https://news.ycombinator.com/item?id=40316010 - May 2024 (114
       | comments)
       | 
       |  _Elvish Scripting Case Studies_ -
       | https://news.ycombinator.com/item?id=39549902 - Feb 2024 (1
       | comment)
       | 
       |  _Elvish is a friendly interactive shell and an expressive
       | programming language_ -
       | https://news.ycombinator.com/item?id=24422491 - Sept 2020 (49
       | comments)
       | 
       |  _Elvish: a shell with some unique semantics_ -
       | https://news.ycombinator.com/item?id=17987258 - Sept 2018 (1
       | comment)
       | 
       |  _Elvish 0.11 released_ -
       | https://news.ycombinator.com/item?id=16174559 - Jan 2018 (1
       | comment)
       | 
       |  _Elvish: friendly and expressive shell for Linux, macOS and
       | BSDs_ - https://news.ycombinator.com/item?id=14698187 - July 2017
       | (86 comments)
       | 
       |  _Elvish - An experimental Unix shell in Go_ -
       | https://news.ycombinator.com/item?id=8090534 - July 2014 (75
       | comments)
        
       ___________________________________________________________________
       (page generated 2025-05-04 23:01 UTC)