Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

So I should change my shell, have it deployed everywhere, and learn a new language so that I can change:

    for x in *.jpg; do
      gm convert $x ${x#.jpg}.png
    done
to

    for x [*.jpg] {
      gm convert $x (str:trim suffix $x .jpg).png
    }


After being a fish die-hard for like a decade I finally gave up and learned to embrace Bash for its ubiquity. I realized all I cared about in fish was the built-in autocomplete, colorized output, and history management, which I was able to bolt on in short order to Bash.

Now I use ble.sh [1] and Oh My Bash [2] and Atuin [3] and I love it.

This is really a field where I feel standardization is the better path. It's a similar feeling I get when I observe the vast array of notetaking apps I see made and think here is a place where it would be better to pick one FOSS solution and contribute.

[1] https://github.com/akinomyoga/ble.sh

[2] https://github.com/ohmybash/oh-my-bash

[3] https://atuin.sh/


> It's a similar feeling I get when I observe the vast array of notetaking apps I see made and think here is a place where it would be better to pick one FOSS solution and contribute.

I feel the opposite -- I use a commercial note-taking app for the same reason I use bash. It kinda sucks, but it's on all my devices, and the extra work imposed by the suckiness is more than made up for by familiarity and by not having to invest any energy to make it work seamlessly across my devices.


for note taking I've had best results with just markdown files and basic text editors (vi/vim/nvim, helix). At this point, actually one single notes.md file, and I can just lazily search through that to find what I'm looking for.


Assuming the first example is in Bash:

- You're not quoting your variables properly to prevent splitting and globbing.

- In case there are no jpg files in the working directory, Bash will put the pattern itself (*.jpg) into the $x variable. You need to explicitly check that the file in the variable actually exists before working on it.

Modern shells do not have these footguns.


> In case there are no jpg files in the working directory, Bash will put the pattern itself (*.jpg) into the $x variable. You need to explicitly check that the file in the variable actually exists before working on it.

Indeed that's one thing Elvish has better defaults that I forgot to mention in https://elv.sh/learn/scripting-case-studies.html#jpg-to-png...., and now I've added that, thanks :)


The latter can be avoided with “shopt -s failglob”.


Why the hostile tone? I don’t see anything on the website saying you should do it. You could, though, up to you. I doubt the authors had you in mind specifically when they wrote the tool.

They made something new and non-detrimental and are sharing it with the world. It’s fine if it’s not something you’re going to use. I won’t either, but I’m failing to see the point of ridiculing their effort.

Your example seems unfair, too. It’s not like that is the only use-case on the homepage.


The thing is, the first example doesn't handle many edge cases which normally arise and are a common source of bugs and security vulnerabilities. The second example doesn't suffer from those issues by design.

In other words, it's OK to type the first example on the command line and it'll work just fine (and if it won't, you'll be able to step in and fix). But running it as part of anything automated would be haphazard.

As I read this, the whole point is that you have something that feels quite familiar syntactically to a common shell, but sane. Kudos to the author!


At this point, I'd just use Tcl:

  foreach x [glob *.jpg] {
    exec gm convert $x [regsub {\.jpg$} $x {}].png
  }
(bonus, you can use `foreach x [glob *.jpg] y [glob *.png]` to iterate on more than one list at once)

The truth is: if you choose to use something rarer than a ten-leafed clover, you better have massively good reasons to do so. Otherwise, there are already other languages with good subprocess integration; pretty sure Guile would do the trick too.


Tcl is actually an inspiration for Elvish, and Elvish has a "command language" flavor too.

The "everything is a string" idea sadly turned out to not work that well for most people though, so Elvish has lists, maps, and first-class functions :)


Modern Tcl has all of these, you know? "Everything is a string" should actually be "everything has a string representation allowing for lossless roundtrip", but it's a bit less snappy; maybe you mean the lack of typing and I'd kind of agree with you here, though it's what makes Tcl's weird homoiconicity work.

Tcl lists are arrays (and kind of deques since https://core.tcl-lang.org/tips/doc/trunk/tip/625.md), dicts are the first-class maps we should have had since the beginning and apply allows to build closures around it.


> (bonus, you can use `foreach x [glob *.jpg] y [glob *.png]` to iterate on more than one list at once)

I don't know about Elvish, but globs in bash aren't part of the loop syntax, they're their own thing, so this also just works:

  for x in *.jpg *.png


This just concatenates the lists, in Tcl (or CL's loop), you can iterate on multiple lists in parallel. Like Python's zip, but cleaner since you don't need said zip.


I would invite you to read the explainer for this script: https://elv.sh/learn/scripting-case-studies.html#jpg-to-png....

Maybe you're not as traumatized by the thousand small cuts when writing traditional shell scripts as I, and that's fair :) However, I'd also invite you to read the rest of the examples, which go into the deeper advantages.

I'd also say that you don't have to "change my shell, have it deployed everywhere, and learn a new language" to start adopting Elvish! It's very easy to get Elvish (https://elv.sh/get/), and you can start using it on one machine, or for one script without "switching" 100%. Think of it as another tool you can use alongside whatever shell you are using (I'd also refer you to the other comment I posted: https://news.ycombinator.com/item?id=40317203).


Thanks for that succinct visual. Would be nice to have a side-by-side comparison like this for all the popular and up-and-coming shells. Really helps since the final choice is often influenced by style preference.


You can find this in the explainer linked from the example too :) https://elv.sh/learn/scripting-case-studies.html#jpg-to-png....

https://elv.sh/learn/tour.html also has a big list of syntax comparison between bash and Elvish.


Thanks, but I was thinking more along the lines of a single semi-complex script, like what https://todomvc.com/ does for selecting a framework.


So according to you, there should be no innovation, never?


No, but innovation should be major, not cosmetic.


I would invite you to read the rest of the explainers, which go into deeper differences: https://elv.sh/learn/scripting-case-studies.html

Re "cosmetic" - I'd agree that the extent syntax matters is more limited compared to semantics, but that limited extent can be a lot of the daily experience with a language! I've ported many bash scripts to Elvish and I still find it liberating to not have to write double quotes everywhere for my script to handle whitespaces correctly.


The biggest innovation here (shells centered on structured data rather than strings) comes from PowerShell. But PowerShell sucks as an interactive shell.

I see the basic concept for Elvish as PowerShell's language power, but with the more Unix-y sensibilities of traditional shells, plus, crucially, the human-friendly focus on rich built-ins for interactivity exemplified by fish.

I don't think a real-world implementation of that kind of idea is a 'merely cosmetic' innovation. There's real novelty in that synthesis. How to balance those inspirations is not obvious, and neither is how to fill the gaps between the big picture ideas and a usable tool.

Go use Elvish for a while and you'll see how much creativity has clearly gone into it. Hell, just browse the GitHub issues and you'll see.


The whole point of an interactive shell is cosmetic convenience.


It's not cosmetic in this case. As others have already pointed out, the elvish version handles a few minor but important special cases that bash does not handle.


and perhaps that's why today's shells are not very far from the shells 20 years ago.


I don't follow. How does the one explain the other?


The second example was more unfamiliar, especially with the bespoke `{|h|...}` syntax. But yes, the first example looks...the same as a bash for loop.


There are explainers linked from each of the examples - in this case https://elv.sh/learn/scripting-case-studies.html#update-serv.... Hopefully that clears up things for you!


> especially with the bespoke `{|h|...}` syntax.

It’s similar to Ruby.


And vaguely reminiscent of Smalltalk, which I'd guess is where Ruby got it from.


Elvish's lambda syntax used to be [arg]{ ... }. But since [arg] is also the syntax for lists, it can get confusing - so I decided to move the argument list inside { ... }. And going through all the metacharacters Elvish already had, | was the one that was meaningless at the start of the lambda body, so I settled on {|arg| ... }.

I only realized the similarity with Smalltalk after that. I did learn a little Smalltalk many years ago but completely forgot about it, but it's possible that the knowledge was always somewhere in my subconscious brain.


To be fair, all examples on the home page look kind of trivial in bash as well, which is why - to me - they seem a bit silly.

    var hosts = [[&name=a &cmd='apt update']
                 [&name=b &cmd='pacman -Syu']]
    # peach = "parallel each"
    peach {|h| ssh root@$h[name] $h[cmd] } $hosts
is

    hosts=( \
        "host_a" "apt update"  \
        "host_b" "pacman -Syu" \
    )
    printf "%s\n" "${hosts[@]}" | xargs -L2 bash -c 'echo ssh root@$0 -- $*'
and

    ~> var project = ~/project
    ~> rm -rf $projetc/bin
    compilation error: variable $projetc not found
is

    set -u
    project=~/project
    rm -rf $projetc/bin
    bash: projetc: unbound variable
Now of course, there are a lot of edge cases in bash, especially around escaping and quoting, which are not handled in my crude examples.

What annoys me with these new shells, is that they dont solve any issue of the real world.

Yes, your language is cute.

Yes it's safer and less error prone that bash, there's no denying that.

But it does not - and most likely will never - handle the trillion - arguably hacky - things that can are done in bash, because that would suddenly completely overbloat the language, multiply its complexity, etc.

Essentially that means it will always be some kind of niche toy with a couple of enthusiasts, while the rest of the world keep on sticking to bash, and overall nothing moved forward.

Now don't get me wrong, I'm all for writing toys. I also have hundreds of my own reimplementations of stuff just because it's fun to code, you learn stuff, etc. But I don't get the "I'm going to create a fancy website, build a community and post it on HN" vibe.

If you seriously think the shell scripting world need a refresher, then the real issue, and we all know it, is not the fanciness of the language. That's the fun part.

The real, actual work, is to provide a realistic path forward. Either by working on bash to improve its syntax to something more modern, maybe through `set` flags to keep backward compatibility. Or to write a transpiler to bash, but with safer and stronger semantics.

This is the actual path forward, and it's the _not fun_ part, it's grunt work, and nobody does it, meanwhile we can sit and use a shiny shell while complaining how bad and unsafe bash is.


While I don't agree with most of your analysis - in particular for the second example, I'd invite you to read its explainer that goes into much more depth (https://elv.sh/learn/scripting-case-studies.html#update-serv...) - I think you might be more interested in the Oil Shell project, which is trying to chart a smooth upgrade path from bash: https://www.oilshell.org

I think we simply can't say for sure which path is better for the future of shells, and I'm quite excited by the fact that different projects are exploring different directions. I will just stick to the path I find best and won't try to convert you :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: