Hacker News new | past | comments | ask | show | jobs | submit login
Fish shell 3.0 (github.com)
506 points by faho 6 months ago | hide | past | web | favorite | 220 comments

Apart from the other good stuff in this release, I think this will make a lot of things much easier:

fish now supports && (like and), || (like or), and ! (like not), for better migration from POSIX-compliant shells

Finally! Fish 2.x shows you a message along the lines of "use `and` instead of `&&`", which is infuriating - it clearly knows what I want to do, and refuses to do it. I love fish and use it as my default shell, but I'm glad to see the fish team take a few steps towards bash compat.

Just because a language knows what you mean to do and can give a specific error messagr doesn't mean that, in general, and specifically, the developers want to commit to supporting && as valid syntax forever.

Perhaps the language creators have plans for future syntax that would not allow what you want. Even if for now the language evidently knows what you mean from the error message.

In this specific case, the developers of fish apparently decided && was good to add.

That reminds me of the very specific nag messages I get from Python 3 when I don't write parens around parameters for print... do what I want already.

What does someone want if they write "bar = print foo,"? Is it the same if "print" isn't the built-in function?

Operator precedence isn't really a new concept, and Python relies on it in plenty other situations:

    bar = 1 + 1
I do believe Python made the right call, actually: print needed to be unified with functions, and dropping the requirement for parenthesis for function calls would have introduced so much incompatibility as to make the Python 2 -> 3 transition far more difficult.

But ignoring the legacy issue, there is a better way to do function calls, and it is ruby.

What does operator precedence have to do with this? Ending a parameter list with a comma changes the output of the print keyword but not a function. Assignment statements can contain function calls but not the print keyword.

C style function calls are common, explicit, and consistent. Python adds the best combination of positional, variadic, and named parameters of any language I know. ML style has less punctuation and simpler grouping rules. Ruby has the weaknesses of both.

Haskell/ml/caml do it better than Ruby.

    f 1 2
    (f 1 2).thing
Here the parentheses are nothing special, they just hint precedence.

As opposed to

    f 1, 2
    f(1, 2).thing
Awkward special-case commas and parentheses.

Didn't Ruby borrow it from Perl?

And lisp, just less parentheses

That usage doesn't get the weirdly specific error message though. It's only the Python2-ish statement that gets one.

What does someone want "print foo" to do if "print" is a different function?

What does someone want "print (1, 2)" to do if "print" is the built-in function? It prints a tuple in Python 2 and ints in Python 3.

I get that. So the Python 3 interpreter has to assume that when I say "print (1, 2)", I actually mean, print these two individual arguments.

If I say "print 'foo'" though, it recommends "print ('foo')", but doesn't go all the way to assume I actually meant that. There's a piece of code handling that special case that stops short of actually interpreting what I apparently mean.

The frustration around that was the original point.

In Python 3 there was an explicit decision not to support print as a statement, and rather as a function call.

You missed the point... that decision should have been made.

Though I've really grown toward the 'everything as a function' pattern that Fish is trying to do, this is definitely a step back in the right direction. I might even wish for `$()` to be supported as well to allow even better copy pastable oneliners from Bash.

I thought it was to be included in 3.0, there's certainly an issue on it.

Your quoting is a bit confusing, as "`cmd...`" and "$(cmd...)" are similar,, while backtick-dollar-paranthesis is just asking for trouble... ;)

I take it fish didn't / doesn't support either?

Sorry for the confusion, I'm to used to `` as code style for markdown, forgot HN doesn't support it. I'm glad Fish doesn't support the backtick syntax :). Like others mention it just drops the dollar from a 'regular' parenthesis expansion.

Fish uses parentheses for command expansion, so backticks aren’t supported and the dollar sign is only for variable substitution.

Fish just uses (cmd), no $.

Ah, which I guess is why no subshell support?

There are other ways to do subshells than using the same syntax, just that the Fish developers never did it, maybe because it's not requested enough. I think it's still the most annoying thing about Fish, and the most convincing reason to switch away again. I frequently drop into bash to do

    (cd subdirectory && command --that might.fail) && run --command-in-original-dir --only-if-subshell-succeeded
... and expect to still be in the original dir when it's done. Any solution in Fish using "&& cd -" at the end of a block AFTER a maybe-failing command is just wrong, and there seriously isn't any way except saving and restoring $PWD every time you want subshell functionality, or using "; cd -" and manually saving the $status, which is equally as frustrating.

There are some non-syntactic suggestions in https://github.com/fish-shell/fish-shell/issues/1439

This is absolutely thrilling! I often have to flip between bash and fish due to some archaic tools we wrote relying on bash in wierd ways, and the swap between how both handled logic like this was cumbersome. Glad to see one less potential reason my team won't use fish.

awesome! can't tell you the number of times I have slammed into this when copy/pasting.

I upgraded with homebrew to v3.0 but the && syntax still doesn't work, do I have to do something special to enable it?

Close your shell and open it (or run fish again). You’re probably still in the original fish 2.7 that had previously launched. fish --version should show 3.0.0 (edit: yeah, that’s not going to work).

`fish --version` showed 3.0.0, after brew update but without closing terminal, but `ls && echo finally` still didn't work. However, closing and re-opening terminal, it now works.

`fish --version` starts a new fish that prints _its_ version.

You were still running the old version, and `echo $version` would have told you.

Hah, oops, should have realised that.

Because you still run the old version as your shell, from which you run the new version merely to have it print its version.

Awesome! I remember bumping into the github issue over it but I guess I didn't read far enough (or maybe it was long ago) to see that they were finally going to support && and || instead.

That’s new? Suddenly I feel less guilty about dodging coworkers who have been trying for years to get other people to try fish.

But maybe now it’s getting closer to production readiness.

The fact that it doesn't support your particular preferred syntax doesn't mean it's not production-ready.

> your particular preferred syntax

I think it's called POSIX.

You seem to be making some sort of argument, I just don't know what it is. Are you saying that fish is not production ready because it's not POSIX-compatible?

It's still not POSIX compatible, deliberately.

I‘m not switching to fish because of its lack of POSIX compliancy. This is a valid complaint.

It is!

But calling it "getting closer to production readiness" feels a tad insulting.

It's probably just a bit of snark, so it's not worth getting up in arms about, but it's not really friendly phrasing.

Fish uses (and still supports) `command1; and command2` instead of `command1 && command2` (and similarly for `||`/`or` and `!`/`not`).

The syntax is different, the semantics are the same.

It's 13 years old it's been production ready for a very long time. Using your preferred syntax != production ready.

If you feel productive with your current shell, stick with it, it is definitely a performance hit when switching shells. That being said, if you have a weekend, go for it, I won't switch back.

looks like i'm switching back to it again from zsh

Oh yes

My favorite feature of fish is `abbr`, e.g. `fish abbr --add g git`. Then you type `g` followed by space and it just expands it to `g` and you then get all the autocomplete goodness and don't have to futz with adding autocomplete support to an alias, because it is the real command. It also helps for presentations because instead of some obscurely named alias, you can type an abbreviation and it just expands it out for the viewer to see and learn from. On top of that, I make abbreviations with long options, that way I can see exactly what is going on and effectively edit the commands.

You can also type fish_config to launch the fish config web app in your browser. From there you can add, edit and remove abbreviations from the “abbreviations” tab directly.

I find this a really user-friendly way of managing abbreviations I've created.

zsh also does correct autocompletion for aliases, if you enable the counterintuitively-named 'no_complete_aliases' option

Nice, thank you. I have been using fish for a long time, but wasn't aware of these.

Have defined the following:

  abbr -a gp 'git push' 
  abbr -a k kubectl
  abbr -a n 'npm run'
  abbr -a y yarn
  abbr -a m make

Now, when I type n, then SPACE, then TAB, I can get the list of npm tasks for example.

After 15 years, I still struggle to test if a string is empty in shell languages. Do I use square brackets, double square brackets, equal sign, double equal sign, test -n, set -q, wtf mate? Do I need to wrap my string variable in double quotes? single quotes?

Fish looks great, and I'm going to give it a try, but I ran into these same old shell scripting issues within 2 minutes of trying to configure my prompt, which is a bummer. Took me 10 minutes (I'm ashamed to say) to end up at `if test -n "$git_branch"` (double quotes are critical).

I'll be excited when someone invents a shell that feels natural in this respect. Perhaps the nature of shells and commands makes this impossible? Or are we just stuck in a box?

It feels a bit more natural once you've bent your mind enough to understand what the shell is doing.

The trick is that `test` and even `[` (which is essentially another name for `test`) are ordinary commands, that exist as stand-alone binaries as well as identical-behaving built-ins. They masquerade as syntax, but they're really not. You can even call them from other, non-shell languages:

  >>> from subprocess import run
  >>> run(('/usr/bin/[', '-n', '', ']'))
  CompletedProcess(args=('/usr/bin/[', '-n', '', ']'), returncode=1)
  >>> run(('/usr/bin/test', '3', '=', '3'))
  CompletedProcess(args=('/usr/bin/test', '3', '=', '3'), returncode=0)
That means that they're not allowed to do anything to variables, because the variables are inside the shell. `test` doesn't see `"$git_branch"`, it only sees the content of the variable.

Per the normal rules, `"$git_branch"` is an empty string iff $git_branch is empty or unset. Leaving the quotes off can do unexpected things, though a lot less so in fish. Using single quotes means you get a literal string, without any substitution.

You're just looking for an empty string anyway, so you might as well use the equality operator instead of digging through the 18 (!) unary flags prescribed by POSIX. So I'd write either `[ "$git_branch" = "" ]` or `test "$git_branch" = ""`. Some implementations support `==` as another way to write `=`, but `=` is standard.

This modularity makes the shell simpler, but it's not exactly sane. I think that providing `[` was a mistake, because it doesn't look like a command, but maybe having `test` as a command is better than having special expression syntax just for these cases.

There are a few misfeatures in `test`, though.

For instance, one way to use it is

   test somestring
to test if "somestring" is empty. POSIX mandates that test with exactly one argument succeeds iff that argument is a non-empty string, to allow that. Fish's test is POSIX-conformant.

Now, that means that

    test -n
is true! Which is also triggered for

    test -n $var
if $var has 0 elements.

This is a problem and should be improved.

always quote your variables. POSIX won't change this soon, or likely ever.

Thanks for taking the time to explain the details.

If we were to start with a clean slate, could we come up with something natural while still having a clean design with respect to commands? Would it be worth it?

The fact that those details haven't sunk in after more than a decade points to an opportunity for a better design, I think. For example, I can pick up Go, Java, Perl, PHP, JS, Nim, etc and memorize the if-statement details in about 5 minutes. Whether or not anyone would use such a shell, I don't know.

I don't know, but I just use fish for interactive use and write shell scripts using #!/bin/sh.

sometimes I wonder if "native" support for regexes would help this, or if it would just be another instance of https://xkcd.com/1171

regexes describe this sort of thing quite concisely and IMO a fair bit more readably than e.g. bash's string replacement syntax, which looks like

when you want to do the equivalent of


It wouldn't even be another standard; it'd just be another incompatible implementation with its own quirks to be worked around.

yeah, the wide variance in regex engines would definitely not be a positive quality :|

I started using fish around 2013, back when it would occasionally crash and leave stack traces in the console. I'm really glad I stuck with it though. Fish has come a long way and it's totally an amazing shell. I really love all the functionality that's come out of the box and don't really mind learning new syntax if it means I can get away from old cruft.

I made fish my default shell for around a month, and I really liked the smart suggestions of what command I was going for when I started typing. But the "vi" mode had enough incompatibilities that it really irritated me, it was extremely incomplete. Discussions of it with devs went nowhere. Plus, there were incompatibilities in the language that I could never bring myself to commit to memory; I might have if the vi mode were better but as it was I didn't want to get any further invested in it than I was.

In the end I switched back to zsh and enabled "zsh-autosuggestions", which gave me the thing I loved most about fish, without any of the parts that I didn't. There's also some other extensions I'd like to try that enhance history like "McFly" ( https://github.com/cantino/mcfly ), based on this previous zsh-histdb discussion: https://news.ycombinator.com/item?id=15041772

ZSH seems to have broader community support and there's a plugin for basically everything. This is why I chose to stick with it over Fish.

If I just wanted a very simple shell, with good defaults, I'd choose Fish. But much like why I use (Neo)Vim I prefer the DIY approach and have gotten my ZSH to the point over the years (and a hundred scripts later) where I love it.

But ZSH the language is pretty awful and non-intuitive (although way better than bash when you dig into it). Even though I've been writing it for years I still get it mixed up often.

My hope is that Evlish shell will be mature enough soon to use day-to-day, which is the only one I've seen with a modern scripting language (written in Go) and is 10x faster than my ZSH (which is very noticeable): https://elv.sh

Similar story for me, but I consider the POSIX shell language a worthwhile least-common-denominator language. I avoid using bash or zsh extensions except interactively (and in a zsh plugin I maintain [0]).

As I think you need to know the standard shell language anyway, new shell DSLs are a bit of a turn-off to me. If the language is trivial it's not very powerful and if it's powerful it takes time to learn.

That's why I have high hopes for shells that combine tried-and-true programming languages and their ecosystems to a thin shell layer. Like http://xonsh.org or https://docs.racket-lang.org/rash/index.html .

But if I'm completely honest, I think bash will still be the standard choice in 5 years and weird shells you haven't heard of will still be weird shells you haven't heard of.

[0]: https://gitlab.com/code-stats/code-stats-zsh

Quick correction, the actual url for Xonsh is http://xon.sh. My understanding is that xonsh.org is an out-of-date unaffiliated mirror that the author of Xonsh doesn't control :(

Oh, oops. Too bad I can't edit anymore. Sad that the out-of-date site os ranked better on Google for "python shell".

Why not just use fish for scripting? That's what I do as zsh as shell works better for me as well.

Shell scripting finally looks a little saner thanks to fish.

I think vi mode suffers because it's a relatively niche feature - none of the current committers use it as far as I know, and pull requests to improve it are fairly infrequent. It gained t/T/;/,/d{f,F,t,T} in 3.0 in two different pull requests, which represents about 1% of all PRs in the 3.0 cycle.

I don't think it helps that it's this huge target area which (the small number of?) users use a slightly different 10% of, and it can be quite complex to integrate new features into existing editor state.

I tried VI mode on Fish for a while but yeah, I just turned it off and have stuck with the default Emacs mode instead. Been much happier since I did that.

I've been happily using fish for maybe two years now, just as a default shell and not doing anything fancy. Out of the box it is great.

I'm not sure how to feel about only now learning its indexes start at a [1] though (╯°□°)╯︵ ┻━┻

Love it otherwise.

Zero based -> index is offset (natural in low level languages) One based -> index is number of element

Starting at 1 is good for non-programmers, who IMO could benefit the most from switching to Fish. I would love to see a distro using Fish as the default shell for non-root users.

When I’ve been teaching people to program, explaining [0] has been a tragic experience.

Starting at [0] is not objectively better than [1]. I actually believe it is objectively worse.

I would like to hear your counterarguments to https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/E..., which seems to me like a compelling argument.

Everybody has an intuition of lists or sequences, and the idea of something being “first”, snd that being labeled “1”.

When teaching people to program, portraying the idea of “jumping zero steps” into a list to get the first element has been an inefficient embarassment every single time I’ve been present.

Re. Dijkstra’s argument:

1: Everybody has an intuition of an ends-inclusive “from x to y”. Everyone would include 2 and 12 if asked to “count from 2 to 12”.

2: What’s wrong with using three dots? What is pernicious about them?

3: Labeling and length calculations always require a shift of one. If we make the ends compatible with thought-free length calculation, then sequence labeling is always off. If we have intuitive sequence labeling then we need to adjust either end label by one to get the length. The latter approach is far more intuitive. Also, one should just ask the damn computer what the length is. That’s what it’s for. Pardon the language. Especially as we will always want to leave behind and tend to leave behind the abject simplicity of hand-calculating the length of our data from the labels of the bump stops; Our data structures may not even support that calculation. So why couple ourselves to that calculation and sacrifice the ability to have sequence labels make sense?

And why don’t we just have both? Keep array[0] as first, fine, whatever, and add array|1| as first too.

It is a compelling argument for calculating ranges, where the subscript is the offset into the range, which is useful when your data structure has properties like being backed by continuous memory and being passed around as a pointer to the first element. But when treating subscripting as “give me the nth element” it doesn’t really make sense.

It seems to be mostly about math, with the only mention of array indexing being that 0 looks nicer. "starting with 0, however, gives the nicer range 0 ≤ i < N. So let us let our ordinals start at zero"

This doesn't seem to be much of an argument so I'm not even sure what to address.

How would you do something like Python's `x[0:10] + x[10:len(x)]` in a 1-indexed way? [1:11] + [1:len(x)+1]? That's uglier.

  julia> x = collect(1:15)'
  1×15 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
   1  2  3  4  5  6  7  8  9  10  11  12  13  14  15

  julia> x[1:10]'
  1×10 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
   1  2  3  4  5  6  7  8  9  10

  julia> x[11:end]'
  1×5 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
   11  12  13  14  15

  julia> x[11:length(x)]'  # alternatively ...
  1×5 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
   11  12  13  14  15

Others have already given examples of how languages with 1-indexed arrays handle this without awkwardness: end-inclusive ranges. I'll just add that end-inclusive ranges are the standard in natural language as well. For example: "Ages 2-4," "please read pages 16, 20 to 25, and 28 to 29," "1941-1945."

0-based indexing makes sense to me in C where arrays are just pointers and the index is an offset, and doing pointer math is a regular part of the programming experience. But most languages have come a long way from that, and collections such as arrays are much closer to a natural metaphor (a list of things). As such, natural ranges (inclusive) seem more appropriate to me.

You just make ranges end-inclusive, and then it's x[1:10] + x[11:len(x)].

The best of both worlds is when a language provides both end-exclusive and end-inclusive slice syntax, as in e.g. Nim: x[0..<10] is end-exclusive, and it's very clear that it is.

But then you no longer get back 10-1 elements, you get back 10-1+1.

So what? You're going to have off-by-one errors no matter what convention you adopt. Python glosses over it by providing the alternative syntax x[-1] for what you would otherwise have to write as x[len(x)-1]. But it's at least as valid to provide alternative syntax for inclusive ranges. And logically, if the first element of x is x[0], the last element should be x[-0], not x[-1].

Half-open intervals are appropriate when you're thinking of them as subspaces of a continuum. When you're thinking of them as subsequences of discrete elements, closed intervals are usually more natural.

Ruby is the only language I know that really seems to have tried to address the problem, providing different syntax for every way you might want to take a subsequence from an array:

    x[5..8]  # elements [5] through [8], including [8]
    x[5...9] # elements [5] through [9], excluding [9]
    x[5, 4]  # four elements, starting at [5]
If you were working in pure, pencil-and-paper mathematics, you'd choose whether to index a particular sequence from 0 or 1 based on what made your formula look nicer. Both are common. But that's not an approach I'd suggest for a programming language.

One thing I would add - using negative indices to index from end is a bad idea in general, because you may inadvertently end up with a negative index as a result of a calculation that you expected to always be positive - and then instead of an out-of-bounds error, you get silent wrong behavior.

IMO, it's better to have dedicated syntax for index-from-end, as part of the range syntax. Again, Nim does that: x[0..^1] (although unfortunately they didn't make it symmetric).

> IMO, it's better to have dedicated syntax for index-from-end, as part of the range syntax.

This is true, and note that my suggestion requires it -- the only way to distinguish x[-0] from x[0] is to have the parser do it; -0 and 0 are the same number.

I mean, you could technically distinguish between positive and negative zero, if your numbers are all floating points (like JS or Lua). But that would be even more of a horror show.

> Starting at 1 is good for non-programmers, who IMO could benefit the most from switching to Fish. I couldn't disagree more. Any tool where you have to say "all these other tools you are used to just working don't work here" is the last thing I would recommend to a non-programmer.

It would be nice but the distro needs to warn the user that copy pasting some shell script may break and would be nice if a converter is provided from bash to fish script.

Still no auto-escaping or quoting for pasted URLs, that's really disappointing. I respect fish's stated goals of user friedlieness, but I just don't think they've realized that goal in ways that other more mainstream shells have:

    > mpv https://www.youtube.com/watch?v=LBoF1e5YDdQ
    fish: No matches for wildcard 'https://www.youtube.com/watch?v=LBoF1e5YDdQ'. See `help expand`.
    mpv https://www.youtube.com/watch?v=LBoF1e5YDdQ
This, to me, is not user friendly.

For reference, pasting the same URL into zsh with the often touted omz (incidentally I recommend you use antigen instead) auto-escapes the URL to

    > mpv https://www.youtube.com/watch\?v\=LBoF1e5YDdQ

What? That's been in for a few releases!

To trigger it, enter a single-quote, then paste the URL, then close the quote once you're done.

We don't attempt to detect URLs because that can go wrong, and because we don't know your intention. So we use the fact that you're inside single-quotes as the signifier that we should escape things - which also allows this to be used for e.g. pasting shellscript as a literal argument.

I think the post is wanting it to be handled automatically, without having to quote it, that was the intent I got from it.

But yeah, I have had a ton of issues where commands fail because I didn't quote URLs, and in the beginning it wasn't as obvious as it is now. I don't have a solution, just saying that this does add friction for newcomers.

How can detecting URL go wrong? It starts with an obvious prefix and ends at a line end or a space.

If the URL contained a space that is not URL encoded, that would be user's fault.

it's not as obvious as it looks. maybe someone wants to construct urls like this:

    wget http://example.com/files/(basename -s .jpg *.jpg).png
but ( is a legal character in urls, so fish can't possibly predict which use is desired.

There must be a disconnect here, manually entering a single quote, then pasting my URL, then adding the closing quote is precisely what I wish to avoid.

Here is a demonstration about what I'm talking about: https://i.imgur.com/d64lwaB.mp4

> "We don't attempt to detect URLs because that can go wrong, and because we don't know your intention."

That much I've gathered from seeing this issue raised with fish people in the past, and in my humble opinion it's the wrong approach. In this mentality fish is forgetting it's stated goal of being user friendly which should in some cases, mean making sane educated guesses about the user's intent. How often do users of the fish shell paste a string that starts with 'http' and contains a '?' that is meant to be a wildcard? Not very often at all, if ever; fish is now evidently planning on deprecating that ? wildcard so I think the fish devs agree!

The way I see it traditional shells aren't user friendly because they take a conservative approach, doing crap like not enabling fancy autocompletion features out of the box because "what if the user is running on a timesharing PDP-11 and can't spare the CPU cycles?" Breaking from that mental trap is bold and should be commended, but in the case of not escaping pastes I think fish has fallen into that conservative mindset again. zsh/OMZ does it by default and I've never heard of anybody getting screwed over because of it. Fish could and should do it by default too.

> How often do users of the fish shell paste a string that starts with 'http' and contains a '?' that is meant to be a wildcard?

Okay. Now you can do it for http. What about ftp? Or "file://"? Do we detect _all_ kinds of URLs?

And even if we do, and we don't miss some or see something as a URL that isn't, what about _other_ kinds of things? What about shellscript? E.g. if I want to just execute a bash one-liner from the internet, I can do

    `bash -c '`
and paste it and it'll work out. That won't be detected as a URL, because it isn't one.

And I've seen a case of a URL with variables just yesterday (though I admit that's a coincidence):

https://docs.travis-ci.com/user/deployment/custom/ has "sftp://${SFTP_USER}:${SFTP_PASSWORD}@example.com/directory/filename". How do I paste that with the zsh thing? Do I need to go back and edit all of that?

So, instead, we have one rule: If you paste it insde single-quotes, it'll be escaped. If you paste it outside, it'll be inserted as-is (but still not executed). No matter what the contents, no matter where.

> Okay. Now you can do it for http. What about ftp? Or "file://"? Do we detect _all_ kinds of URLs?

Some is better than none, that's the lesson learned from OMZ's implementation of this feature. It doesn't cover every single scenario, but it covers enough to make people's lives easier in the common cases. That is the sort of bold decision making that the fish developers should be doing.

    `bash -c '`
Both of these get pasted unchanged in zsh. I suggest you try it out. But more to your point, this would get improperly escaped:

And you know what? That's fine. Because whether you choose to auto-escape or not, something will break. The question you and the fish developers should be asking is which is more likely? Auto-escaping works the vast majority of the time and only fails some of the time. And when it fail in the rare case, the UX is no worse than when it fails in the common case.

>"If you paste it insde single-quotes, it'll be escaped."

First of all, that's not what I see. Maybe you're talking about bracketed paste mode or something that's invisible to the user, but when I paste a URL containing wildcards into single quotes in fish, I don't see any escaping taking place. I assume single quotes are the "verbatim quotes", e.g. `ls '*.txt'` doesn't show you all txt files because that wildcard isn't expanded inside those single quotes. With that in mind, it's not clear to me why a string pasted into single quotes should be escaped, it doesn't need escaping and I don't see any escaping being done when I try it out myself.

There's nothing magic about making `mpv 'https://www.youtube.com/watch?v=LBoF1e5YDdQ'` work. Dumb old bash accepts that too.

>Some is better than none, that's the lesson learned from OMZ's implementation of this feature.

I disagree. I'd rather have predictability here.

>when I paste a URL containing wildcards into single quotes in fish, I don't see any escaping taking place.

That's because you've not pasted anything that needs escaping. In single-quotes, only single-quotes and backslashes are special, and they are escaped.

Even if you paste script that itself contains single-quotes, it'll work.

The truly unpredictable UX is when a noob tries to paste a youtube url into their shell and gets a bewildering error message about a wildcard (and the error message carrot doesn't even point at the guilty wildcard!) That is very far from the behavior the user was predicting, unless they've been around the shell block a few times already (in which case they could probably make due in a shittier shell anyway. Is fish optimizing for 'user friendly' or 'user friendly for experiences users'?)

>The truly unpredictable UX is when a noob tries to paste

Yes, and you've not solved that.

You've only solved that one special edge-case where they're pasting "a youtube url".

This only pushes the confusing bit further along, and adds some more cruft on top!

Quoting is a fact in shells. The way these languages work is through loads of string interpolation, so you kinda need to learn that. And I'd prefer to make the rules there simple than add special cases for URLs.


> Your dismissive attitude towards this is antithetical to the design of user friendly software

And your dismissive attitude of the project's own design goals is antithetical to the notion that not everybody has the same priorities as you, nor do they think your personal ideas equate to "the design of user friendly software".

The principle of "no surprises" is probably the greatest aspect of "user friendly software" when it comes to power tools such as shells, scripting languages, programming languages, etc. and that seems to be what GP is stating as preferable to edge-case scenario surprises.

You may disagree all you like with that as a priority, but please don't go to the extreme of stating that someone is being dismissive simply because they don't hold your idea up on a golden plinth above their own.

>The principle of "no surprises"

Is violated by this:

    > mpv https://www.youtube.com/watch?v=LBoF1e5YDdQ
    fish: No matches for wildcard 'https://www.youtube.com/watch?v=LBoF1e5YDdQ'. See `help expand`.
    mpv https://www.youtube.com/watch?v=LBoF1e5YDdQ
Particularly for software that sells itself as user friendly. The carrot doesn't even point at the wildcard!

I am very far from the first person to raise this issue with the fish devs, you can find numerous people bringing this up going years back. I'm generally pretty cognizant of when I have unusual requests or opinions about how software should work, and this is not one of those times.

Your proposed remedy is for the shell to insert something different than what the user inputs. That is much more surprising. No program works that way.

No program other than a shell requires that a URL copied out of your browser's address bar be escaped. Users may not be accustomed to a program escaping or quoting text they paste, but they're also definitely not accustomed to escaping or quoting strings manually.

How do you propose that people use a shell without learning about escaping.

How many people actually using fish are liable to be confused.

Its a strange world you seem to be describing where people simultaneously prefer to use mpv in the terminal instead of clicking on a link but can't figure out how to quote the url.

You can actually set it up for example in Firefox so you can open a link in mpv instead and skip a step.

You could trivially make a quoted paste function and bind it in fish.

This fixes the problem for you it would seem.

That is not surprising in any way. It is very clear and defined that a question mark is a wildcard, and will be expanded. If you want a literal string, define it as such with a single quote.

>"It is very clear and defined that a question mark is a wildcard"

To experienced command line jockeys like you or I, sure. To the inexperienced user, knowledge of the ? wildcard is far from given. ? is esoteric enough that fish has apparently decided to deprecate it completely. fish's error message does not indicated that the wildcard in question was ?, nor does it point to wildcard, it only points to the token that contained the wildcard with no indication of which character it was.

That's not the user friendly experience fish advertises.

? Soon won't be a special character most urls don't include [] () >|$ seems like the majority of urls will actually work without escaping.

URL pasting is indeed annoying. That said, second-guessing the user's input is dangerous territory, which is why no shells do what you describe by default.

The way we plan to address this in fish is to make ? an ordinary character instead of a wildcard. Then URLs will have nothing to escape.

You can opt into this change today by setting the 'qmark-noglob' feature flag:

    set -U fish_features qmark-noglob
now ? no longer globs.

>Then URLs will have nothing to escape.

Unfortunately, `&` is used in URLs, and is special also in the middle of a token.

How is parsing "^https?://." a second guessing? It's a URL.

The user inputs ? but the shell inserts \?. The shell would be guessing that the user meant to input something different than what was actually input.

> "That said, second-guessing the user's input is dangerous territory, which is why no shells do what you describe by default."

Sure that's true, but on the other hand I don't see anybody ever recommend default zsh. It seems pretty widely understood in the community that OMZ (or their equivalents, I have unrelated complaints with OMZ) are sane 'defaults'.

To install on ubuntu if you don't want to build:

sudo apt-add-repository ppa:fish-shell/release-3

sudo apt-get update

sudo apt-get install fish


To install on Arch (w/yay), `yay -S fish`. (just a plug for how easy it is to install packages on Arch)

Adding the usual disclaimer that yay is an AUR helper and thus not officially supported by Arch. Arch users are advised to read https://wiki.archlinux.org/index.php/Arch_User_Repository instead. If you know what you're doing, of course using yay should be fine as well.

It should be noted that adding a PPA is equally unsupported, so in both cases you're trusting a third party.

Despite all the disclaimers (or perhaps because of them), the AUR is IMHO one of the more safe and well-thought-out ways of including third-party stuff. It's relatively simple to verify that the package is installing what it says it is, because you can check the PKGBUILD file, which is short and simple to read. I would have no idea how to go about verifying that a .deb file was what it said it was.

`dpkg -L filename.deb` provides a list of files to be installed.

Does yay come default on arch linux?

No, but I'll say that it is the single coolest feature of Arch, and I think it should be default. I have been able to install every single package with a `yay` command except for one.

My instructions I have for installing yay are:

Go to https://github.com/Jguer/yay/releases Download the yay release and extract it, a clone won't have the build files, download the release. cd to the extracted copy ./yay yay (install the AUR copy of yay using your local copy of yay)

Then `yay -S <package-name>` and done, it grabs the repo if it has to and runs the build steps to build from source. It is the most frictionless package management experience I have every experienced on Linux.

And I have used `apt-get` on Ubuntu for many (10?) years (go find the PPA yourself dammit) and also `yum` RHEL7 for the past year. Fedora and Debian need something like this too.

Enough people use it that it would make sense to have it in the official packages. However, having to download and build at least one AUR package (yay itself) manually is an important part of being familiar with the process so that you are more likely to take precautions with third party stuff you later install from the AUR.

Installing an AUR package without a helper (which you have to do to install a helper in the first place) basically amounts to:

    git clone https://aur.archlinux.org/yay.git
    cd yay
    makepkg -si

But then you would have to manually check for updates etc, so the helpers are pretty useful.


Fish Shell has been having some problems implementing process substitution. Last I checked, they tried two approaches:

* piping to FIFO files, but it throws an error if you pump too much data into them

* waiting until one process finishes before starting another. That's not a correct implementation either

Bash apparently resorts to black-magic.

The Bash manual seems to imply that they use /dev/fd to implement process substitution like regular pipes, but passing the pipe file descriptor as its filename under /dev/fd.


Long time zsh user here. Any reason one should try out fish?

Coming from ZSH, Fish is a shell that just worked out of the box for me. It did everything ZSH did but I didn't have to touch a single configuration file to make it work. With ZSH I was forced to find all the options I wanted enabled and tuned or had to resort oh-my-zsh or templates from others to get all the good stuff. Managing dotfiles across workstations and servers. With Fish about the only thing I do after installing is set a theme with Git status.

”Fish is a shell that just worked out of the box for me”

Same here. Fish’s configuration defaults are very well thought out and incredibly smooth. My config.fish is only nine lines.

And when you do want to configure it, you can choose to use either config.fish or the web-based configuration tool. The web tool is very nicely thought out and lets you preview themes and such before you use them.

Yet the thought of a shell with a web interface made me shudder at first. Like those electron based terminal emulators.

It's a python script, using python's http.server. If you're not executing `fish_config` explicitly, nothing is running.

Nice use of the Python http module. Never looked into the function before tbh (didn't expect the server to be running in the shell though). But just did using `funced` (which I just discovered in the changelog, nice feature as well).

It's also great when you need an ad hoc web server:

    python -m http.server

> It did everything ZSH did

... and some additional things that you can't do in zsh without plugins, such as autosuggestions[0].

[0]: https://github.com/zsh-users/zsh-autosuggestions

I have started a lot of unsophisticated shell users with Oh My Zsh which works great without any configuration, and is what I use myself.

I can see how its easier to just make sure Fish is installed, but in some situations (NFS home directory mount and zsh already available) it is easier to install oh my zsh in HOME.


With zsh, I can do ~1, ~2 etc to move around a directory stack. Does fish have anything like that?


Fish does not include tons of syntactic shortcuts. We try to keep the syntax fairly free of opaque symbols.

You can use `prevd` and `nextd`, or you can use key bindings, like the default alt-left and alt-right bindings.

How do you go to the nth item of the directory stack? Even bash lets you do this:

    $ dirs -v
    0  ~/baz
    1  ~
    2  ~/bar
    3  ~/foo
    4  ~/spam
Then "pushd +3" will take you to ~/foo. This hardly seems "opaque".

That's included, just the `~2` shortcut thing isn't.

Which is included? I couldn't find anything like "dirs -v" in the fish manual. Without that, "pushd +N" isn't very useful.

There's a "dirs" command, which lists the directory stack, and a "cdh" command, which lists your directory history.

I made a plugin for that. It works well enough for my needs. https://github.com/danhper/fish-fastdir

I'm not sure how nice zsh is by default, but out of the box Fish is nice, it's just not compatible with bash scripts. I think of it as a really nice shell for terminal use, I wouldn't write "fish" scripts personally, not as portable.

I mostly like that it tells me when my commands are wrong or when it autocompletes (usually hints are based on the directory you're in which is nice).

I tried zsh ages back and if I remember correctly you had to configure it yourself to get to such a point.

Note I only install fish in systems I fully own, I rather not confuse coworkers by using another shell. Also forces me to be more careful when in a production system.

I was a long time zsh user too until a few months ago, when i tried to configure zsh line completion for a new tool. After a few hours of reading and trying I looked at how this other new she'll did it. Found the doc clear and the implementation clean, was able to solve my problem in no time. Havn't looked back although I'm not a big fan of breaking sh compatibility for many futile things, I welcome the simpler design.

Abbreviations!!! No more aliases, abbreviations are the killer feature. See my other comment in this post for an example.

Also, inline function creation, editing and saving are also pretty killer. I make way more one-day use functions than on bash with fish.

I just switched back to zsh after using fish for a while. I found fish nice, but found the lack of POSIX compliance annoying when I wanted to modify things in my rc. I also just like the (oh-my-)zsh defaults better.

Haven't tried 3.0 yet but it had some gotchas back then that I switched back to zsh when zsh could just do all fish could do with enough customization but kept using fish for shell scripting as it looked more sane than the bash like syntax that is ancient.

I use fish for years but never explored it deeply. Mostly I choose it "just works". Auto-completion based on history is great, vim mode seemed kind of silly at first but after I started using it just feels very natural.

There is basically no configuration. It's set it and forget it.

At the very least it is a very well designed piece of software. Even if only for that reason, I would recommend taking a look.

Fish still doesn't support !! or !command expansion.


The bang-bang plugin handles !! and !$


Cool stuff! Love the modest headline on http://fishshell.com/

> Finally, a commandline shell for the 90s

It makes me wonder, how would a shell for 2020 look like?

>? as a glob (wildcard) is deprecated and will be removed in the future (https://github.com/fish-shell/fish-shell/issues/4520)

This surprised me, but maybe it's for the best. It got in my way more often than I used it. I'll still miss it.

It makes pasting unescaped data (read: URLs) and writing raw regexes easier (esp because ^ is no longer a reserved character as well).

huh ... interesting. I missed that. I often quote URLs when running wget because of question marks, and I guess I don't have to now.

You still have to watch out for ampersands though.

The one thing I miss most in fish is subshells, because I love writing things like ( (cd $dir && ./run_prog && cd PKG && ./do_stuff) & ), to run a series of things in the background. Is there any way to do something similar in fish?

What this does is two things:

- It keeps the state separate from the main shell, including $PWD (so the `cd` doesn't affect the main execution "thread")

- It executes some script in the background

Fish's backgrounding is currently limited to single external commands (not even functions). That's https://github.com/fish-shell/fish-shell/issues/238.

It also doesn't have the capability to keep $PWD separate, though other variables can of course be declared locally. That's https://github.com/fish-shell/fish-shell/issues/1439.

The workaround is, if you actually need this, to run it inside `fish -c`. Which is essentially what this syntax is doing in the background anyway (it needs to fork off because `chdir` applies to the entire process).

(Disclosure: I'm a fish developer)

Difference being that the fork is copy on write, so it can be quite a bit faster and need no initialization. Not to mention not needing to quote quotes and escape escapes.

Forking off a subshell is very different, I would think, than forking and execing a new shell, both from a resource standpoint and an open file standpoint.

Not really from a usage perspective though, and resources often don't matter.

If you're doing something like this in the background, then that usually means it takes a "long" time (or you'd just wait for it). So the overhead of starting an additional shell simply isn't important.

Not that it's always irrelevant, but that's why the issues are still open.

Agreed, resources often don't matter.

But I do often do something like:

( cd somewhere ; do_something )

just so I can avoid having to do

pushd somewhere ; do_something ; popd

(or the equivalent).

I also do that, often with loops.

    for ((i=0;i<4;++i)); do (./ad-hoc-operation >out-$i.log 2>&1 ) & done
Can be anything from image processing, video transcoding, file decompression, file system analysis - anything I think may complete faster with some concurrency.

Something like this should do the same thing, I think?:

seq 0 3 | parallel "./ad-hoc-operation > out-{}.log"


With longer expressions, I find the escaping gets tricky. Also gnu parallel has stupid licence problems and the author has told me I can't use it without paying him.

Might do. OTOH I often have a shell pipeline as the body of the loop, rely on glob expansion, etc. For ad-hoc parallelism of a simple command over lots of data, I tend to use xargs -n -P - since I use xargs for other things, I stick with it.

Also, bash and xargs are available everywhere, on production servers as well as dev laptops. Anything that requires installing something has a big hurdle to overcome - this counts for fish too.

That's a nicer notation than me! I thought you needed a ; before the 'done', and & ; won't parse.

I didn't know about subshells. I'm going to be using that all the time now, thanks!

I loved Fish while I used it. I recently stopped using it because I'm writing a lot of documentation. I prefer to do thing using bash or zsh now so I can be sure it will work for others.

I run tcsh. It won’t.

You know you run tcsh. fish users usually know they run fish. You don't expect to be able to run arbitrary copy-pasted shell snippets in the first place.

I try to run my scripts on /bin/sh (on a system where that's not just a symlink to a fancier shell) before posting them. That means it's more portable, but still not universal. I don't typically have bash on my BSD systems, and when I do, they're not installed to /bin, so this is also somewhat out of self interest as well.

Something I've been thinking about this week as a vanilla bash user: Does Fish (or zsh, or others) have the ability to maintain some sort of a global command history? I often find myself wanting to run the same command in multiple terminals and currently just copy-paste.

In fish you can use `history --merge` to merge the current shell's history with other instances of fish.

The sort of global history you want is possible with bash: https://news.ycombinator.com/item?id=3755276

zsh has a SHARE_HISTORY option: http://zsh.sourceforge.net/Doc/Release/Options.html

Not part of a shell but in MacTerm the “command line” window has its own history and it can optionally send the text to all open windows.

Iterm2 on osx supports sending the same inputs to multiple tabs

zsh supports this natively (and is the primary reason I switched to it many years ago).

Is there anything remotely like this on Windows?

I use Cmder / Conemu now but it doesn't seem to have even 10% of the features of a fully fledged shell like this.

cmder and conemu are terminals. They run shells, like bash or zsh, but also fish.

I've not used it myself, but I know that fish is available in WSL and cygwin (though this release had some issues there).

Yeah I realised after I posted that I was talking about terminals not shells but it's too late to edit my mistake away :)

Interesting about it working on cygwin / WSL. Maybe I'll give that a go. I'm sure someone's also made Powershell enhancements that add similar functionality too.

Oh-my-posh + a few custom scripts for better autocomplete that I found here and there. Wasn't very easy to configure and it's still nowhere near my fish shell, but at least it's much better than plain powershell.

So weird. Last night I ran a bunch of updates and spent some time cleaning up and configuring my laptop. Preparing for the New Year. I tried to upgrade Fish and saw that it hadn't had an update since this time last year. I ended up looking through the release logs and just reading the Fish docs a bit. I never do this. Now, this morning, this is on Hacker News.

It's not weird, it's a cognitive bias:

Frequency illusion (or Baader–Meinhof effect): The illusion in which a word, a name, or other thing that has recently come to one's attention suddenly seems to appear with improbable frequency shortly afterwards.


I think it's more like a productive time of year for hackers to get things done :). The week between xmas and new years is always super productive and creative for me... it's quiet and there is a subconscious urge to wrap things up before year end.

Yeah, I was thinking that too but I look at Hacker News daily and at least once a week a coworker bugs me about using Fish. So it's not like the idea or thought is new to me. In particular this one was weird because I was not only thinking about Fish but checking specifically for an upgrade which I've never cared much about before.

Can anyone who's experienced with both fish and zsh comment on reasons fish might be better?

fish doesn't try to support all of the weird historical quirks of Bourne-style shells, so its grammar and built-in 'API' are far simpler and clearer. Its out-of-the-box configuration is much much nicer for most people than zsh's. Completion definitions are easier to read/write. Its source code seems less byzantine. And its GitHub-based development model is more accessible.

The down side is that it's functionally very limited compared to zsh. fish's completion functions are easy to maintain, but the trade-off is that they don't offer the fine-grained contextual control over behaviour that zsh's do. Features like globbing, sub-shells, job control, co-processes, modules, &c., are absent or extremely limited. There are fewer knobs and switches, though as mentioned it tries to do the right thing for most people by default. And a consequence of the syntax being clearer is that it's also much more verbose, which i guess you may or may not appreciate.

Over-all i think fish is a good shell for the (very common) type of person who doesn't really care about shells but was drawn to zsh just because it has nicer completion than bash and lets you write fancy prompts. I don't think it's a good fit, yet, for people who write complex scripts or regularly make use of stuff like extended globs, background jobs, and fancy parameter expansions.

Job control should be fully featured - backgrounding, stopping/continuing, and disowning are all implemented. If there's something missing we'd definitely look at adding it.

Yeah, you're right of course. I think i was conflating job control with sub-shells, sorry.

For me it's the out-of-the-box autocompletions just work really well. Not sure I had the ultimate zsh completions setup before but I did try and was not able to get anything near as good as fish.

It's like fish can read your mind.

Shell scripting finally feels sane. Just the normal "if" and other basic conditionals make you feel you want to switch.

Some scripting example : https://nicolas-van.github.io/programming-with-fish-shell

(I use zsh as shell, as enough customization can do much of what fish can achieve with bit more stability but maybe they fixed with 3.0 which I haven't tried yet.)

This is nice and everything, but I don't see why you would write fish scripts in the first place. For anything like that I'd use python, and imo the only reason to do POSIX shell scripting is that a compliant shell is probably preinstalled on your target platform.

How do people manage scripts to be used in such niche shells? I started using zsh at work recently, while I quite enjoy the shell experience it is a pain to rewrite all bash scripts to zsh or add lines of codes for compatibility. Any pointers?

You don’t. ;-) Use fish/zsh interactively, sh for simple scripts, Python for the more complex.

Yeah I get that. But this method doesn't help for scripts that need to modify the current session state (such as export session variables). I am guessing here that such scripts are an edge case and most shell scripts can be simply executed with sh.

Could you give a concrete example of a situation you have in mind? If I'm understanding you correctly, then one solution could be to create a small wrapper to exec bash, source your environment-modifying script, and then exec fish. Are you familiar with exec [0]? fish also has an exec command [1].

I've been using fish for years and it hasn't been an issue. You can keep bash installed for any hardcore scripting, and just fish as your interactive shell.

[0] https://stackoverflow.com/a/38581329

[1] https://fishshell.com/docs/current/commands.html#exec

Most scripts are run, not sourced. Some tools support fish. bass[1] aims to handle the rest.

[1] https://github.com/edc/bass

I like fish's auto completion speed and smoothness but one thing that has held me back when I checked out fish was that there didn't seem to be a `Ctrl+r` command that bash and zsh provide to quickly go through history commands.

You start typing what you want, then hit the up arrow to fuzzy search back through history.

Is this the only way? Arrow keys require I take my fingers off the home row, which is far from ideal with the frequency I search shell history.

Control-P does it too, and is what I normally use. (Generally, I use control-{n,p,f,b} instead of arrow keys wherever possible. I also have caps lock mapped to control.)

fzf [0] has a history mode included and integrates nicely with fish. You just need to enable the fzf bindings [1], then CTRL-r will give you a (fzf) history searcher.

[0] https://wiki.archlinux.org/index.php/Fzf#fish

[1] https://github.com/junegunn/fzf

Does anyone know how it compare to zsh with oh-my-zsh?

Zsh + OMZ is a slow, unconfigurable mess. If you are new to Zsh, avoid OMZ. If you are experienced with Zsh, you already know to avoid it.

Fish "just works", and you won't have any lag. It is a delightful beginner experience, too.

A Zsh veteran could probably replicate parts of the Fish experience in Zsh, but ultimately they are different tools. I use Fish at home for casual shell stuff, but I write shell scripts in Zsh, and I use Zsh at work whenever possible.

I guess I try to switch to fish again as like you said zsh with 10 plugins takes so long to start a shell, like 5 seconds which feels forever when you want to start typing right then, that I now never quit the shell from remote machines but just disconnect from its tmux instance so I can go right back without initializing the shell every time I log in.

This is also a result of bad plugin design.

Functions should be on fpath, zcompile'd, and loaded with autoload. Otherwise you have to read and parse 100s of lines of code every shell invocation... yikes.

I much prefer fish to zsh + omz. Most of the functionality is built in, and there are plugins for any missing ones (nvm is a big one).

I never got nvm working for me, so after a few years on fish, I switched back to ZSH just for nvm. Any tips on how to get it working?

I think it had to do bass not working though, so the plugin didn't work. Now that I'm on NixOS I might give it another shot.

   fisher add FabioAntunes/fish-nvm
worked for me!


Well, https://github.com/oh-my-fish/oh-my-fish exists if you want.

even I am curious to know as well. some things I have found are fish is very fast, comes with syntax highlighting and auto suggestions from history.

one thing I have noticed is, some packages (I can't remember which, perhaps it was virtualenvwrapper?) come with tools which work with bash or zsh. I have rarely seen fish being mentioned.

edit: it was gcloud sdk and it added command line completions:

  # The next line enables shell command completion for gcloud.
  if [ -f /Users/avi/code/google-cloud-sdk/completion.zsh.inc ]; then
	source '/Users/avi/code/google-cloud-sdk/completion.zsh.inc'

I was hoping to see that they added a `time` command, which is something that makes me change to bash every once in a while.

There's an actual program, usually installed in /usr/bin/time. The shell builtin is not really necessary.

There's an outstanding issue in the github because the binary doesn't let you directly time fish functions. You can do

time fish -c '[function]'

but that includes the time to launch fish.

This, of course, wouldn't matter for any reasonable usecase but I like a fancy prompt and don't like waiting for it to run.

Ah, timing other shell functions is a use case I hadn't considered. Yes, then you're out of luck I suppose.

I think $duration is a thing, which is the time it took to run the previous command. It doesn't separate things like time does, but it's still useful for some cases.

In fact, I customized my prompt to pretty print the previous command's duration if it took longer than 3 seconds or something like that.

I use the Spacefish prompt plugin[0], which does that as well, and comes with a whole lot of other goodness!

[0] https://github.com/matchai/spacefish

Let me know when it's posix compliant.

As soon as your bash scripts run with /bin/sh.

You can still have bash installed and anything that requires significant scripting could probably be done easier with a language for scripting. I want my shell for my terminal. This is also the reason I don't like the verbosity of Powershell, however much an OOP paradigm better supports scripting.

You can write scripts in the semantics-preserving common subset of POSIX sh and bash, which is not quite, but close to exactly POSIX sh.

It's a widely-touted meme that scripting is more easily done in a general-purpose language than in a shell, but this is mostly true of the (common!) category of tasks which use the shell to launch sed &c. to perform string processing which is built-in in general-purpose languages. It's comparatively hard (i.e. verbose and error-prone) to replace a shell language with a general-purpose language in its core competence, viz. launching processes, muxing I/O, and coordinating parallel processing.

Probably never. Just use a shebang for scripts,they exist for a reason.

Registration is open for Startup School 2019. Classes start July 22nd.

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