More to a specific point: I haven't had much of an issue with fish's subshell/backgrounding control. That doesn't mean that there aren't issues, just that my interactive use doesn't trip into them.
I will note that you can write an async git prompt using nothing but fish itself, which I consider an advanced use case for a shell. Check it out:
https://github.com/pirate/fish-functions/blob/master/backgro...
https://github.com/pirate/fish-functions/blob/master/progres...
https://github.com/pirate/fish-functions/blob/master/signal....
https://github.com/pirate/fish-functions/blob/master/fork
Usage:
background progress_await compiling_task_finished
g++ ... some slow command
signal compiling_task_finished
This allows the progress bar to truly run at the same time as the g++ command and receive a signal from the fg process when it's time to complete, something a simple & does not let you do in fish.I've collected more details on Fish's issues here for anyone interested:
Confession: I haven't taken pains to learn any shell after that. Almost similar to why I never took to try out VSCode after getting used to Sublime Text. So many demos, videos etc. quite tempt me to try out VSCode but still haven't ever got to it)
The only thing that I took note was to install https://github.com/oh-my-fish/oh-my-fish every time I setup a machine.
Would be great to know of any quick to learn fish-hacks or fish-for-dummies resources
* get comfortable with stdin/stdout/stderr syntax (and redirection)
* get piping down pat. It's so useful.
* practice using &&, ||, and ; to sequence commands
* know how to use ENV=value to override env vars, and understand how env vars work
* yak shave a bit and make some aliases/functions in your shell based on your usage patterns
From here, it gets esoteric pretty fast, no matter what shell you're in. But you have enough concepts to figure out you need from there.
- Make a file named ~/.config/fish/functions/foo.fish
- Inside it, define a function named "foo"
That's it. Now when you open a new shell and try to run the command "foo", Fish will look for the file named foo.fish in that directory, load and execute it, then call the foo function from in it.
Now, create an autoloaded function in Zsh or Bash without looking at a man page.
There are a million little niceties like that where I'd assumed that a certain task had to be complicated because every shell I'd used before had made it complicated, but then Fish came up with a nice convention for making it simple. Want to make a function to dynamically set your shell's prompt? Create a function named "fish_prompt" in the file ~/.config/fish/functions/fish_prompt.fish. Ta-da - turns out it doesn't have to be a pain in the neck to do that.
I completely agree about using it as a scripting language, though. It's great for making functions for your interactive shell, but stick with sh or bash (or Python) for writing more sophisticated stuff.
For zsh:
- Make a file named ~/.config/zsh/functions/foo
- Inside it, define the body of the function for foo
- Add ~/.config/zsh/functions/foo to $fpath with "fpath+=~/.config/zsh/functions"
- Declare foo with "autoload -Uz foo"
> Want to make a function to dynamically set your shell's prompt? Create a function named "fish_prompt" in the file ~/.config/fish/functions/fish_prompt.fish. Ta-da - turns out it doesn't have to be a pain in the neck to do that.
To do the same in zsh:
- define a function (can be autoloaded or not) named prompt_foo_setup to change your prompt
- add the following to your zshrc: "autoload -Uz promptinit; promptinit"
Now you can easily change to your custom "foo" prompt by running "prompt foo".
There are many valid points which make zsh (or bash) hard to use out of the box, but neither of the points you've raised are one of them. One can easily do both without "looking at the man page."
For context, for a while I was the FreeBSD port maintainer for shells/bash-completion. I'm (too) familiar with the plumbing of various shells. I can do all the manual work myself, but there are lots of things I'd rather be doing instead.
How do you know which flags to autoload to use without reading the docs? How did you know to call autoload?
The point is, it's trivial to create an autoloaded function in both fish and zsh. You don't have to look at the man page each time, which is what was being implied in the comment I was responding to.
But to answer your question, you never need to call autoload with flags other than "-Uz" 99.99% of the time. So the idea that you have to consult the manual each time to figure out the flags is plainly not true. As for the fact that you have to call autoload to bring autoloaded functions into scope, what else did you expect? Fish's behavior of bringing undeclared functions into scope isn't exactly intuitive either.
funced foo
funcsave foo
funced will either allow you to edit it inline, with a clever multiline system, or through your $EDITOR.funcsave will record the file to the place you want once you're happy with the changes.
Which means you can funced as many times as you want on both new and old alike until you're happy with the function.
funced foo
Then edit your function in the editor, save and close it, and then: funcsave foo
to make sure it's there in the future sessions. Without that second step you can create one-time helper functions for the active session. for fname in $(ls ~/.config/zsh/functions); do source $fname; done
:)GP is talking about JIT loaded functions: 'that is, not defined in your shell's rc file'.
will prevent issues with special chars and spaces in filenames
I also prefer the basic syntax for things like for and while looks on the command line, the way they get formatted. With bash I always had to look up the syntax because I didn't use it much. Fish, I barely have to look up things because they are pretty intuitive, for the most part.
Also, no adding `export X=Y` to your .bashrc because you can just `set -U` and it automatically saves it between sessions.
You say that but I'd been writing a shell in my spare time and I solved those problems over the course of a few weeks. For me though, they were important problems to solve because few other lesser mainstream / alternative shells addressed those problems and thus they became all the more tantalising problems to solve. In Fish's case, they might be lower priority jobs.
Unfortunately though, I also broke job control support again earlier this year and haven't had the spare time during the pandemic (my kids have been understandably more demanding of my time now that I'm working from home) to fix it. So I can't demo that particular feature as working. As an aside, this is also a good lesson to everyone to write robust tests....
# these behave the same in bash but differently in fish
some_command & # this works
some_function & # this does not
The relevant issues are listed here if you're curious about why it's difficult to implement this in Fish: https://github.com/pirate/fish-functions#issues-with-fishJust set up TabNine, what are the other 3?
Over the years I've amassed hundreds of fish functions for common tasks on my machines, https://github.com/pirate/fish-functions. I loved it so much I started using it to write devops/deployment scripts instead of bash. That was a mistake.
It has some serious limitations as a scripting language, namely lack of proper subshell support and background process control. The relevant issues have been open for years with no clear resolution in sight. (which is fair, these are very hard problems and it's an open-source project with finite resources)
That's fine though, it's still my favorite interactive shell for use in a Terminal. I just make sure to write any script longer than a few lines in Bash. https://github.com/pirate/bash-utils