Fish shell 2.0
ridiculousfish.com
ridiculousfish.com
There seem to be a number of misconceptions, which I will endeavor to address. The first is: "Fish isn't POSIX/bash-compliant, so there are compatibility problems." POSIX non-compliance is a feature, not a disadvantage, of the fish shell. It means there is less legacy baggage and syntactical inconsistency. I can count the number of POSIX/bash compliance-related issues I've had with fish on one hand, all of which were easily dealt with. For example, Vim assumes that your shell is sh compatible, but adding set shell=sh in your .vimrc solves that. The only other significant one for me was virtualenvwrapper, which doesn't support fish. Not a problem: Virtualfish solves that handily: https://github.com/adambrenecki/virtualfish
Want to run a bash script? Just run bash fooshnizzle.sh. Want to switch to bash for a moment? Run bash and then exit when you want to switch back to fish. This POSIX-compatibility topic is, in my opinion, much ado about nothing.
Another misunderstanding seems to be, "I can do XYZ in bash, but fish doesn't support that." Fish purposefully limits the number of "builtins" -- commands that fish includes by default -- in order to maintain simplicity. For me, that's a feature. When I find that there's something I want to be easier to do in fish, I whip up a tiny function to do it. Not only is that extremely easy to do in fish, but then that command performs precisely the way I want it to. I haven't pushed many of those to my dotfile repository yet, but you can check out some of my fish functions there: https://github.com/justinmayer/dotfiles/tree/master/fish
Fish is fast, the auto-completion is amazingly helpful, and it's intuitive to use without too much configuration. Give it a try. 🐟
Why not just
#!/usr/bin/env bash
? In zsh I never worry about running bash scripts because they run by the kernel with the shell/interpreter specified after the hashbag.I was excited to try fish, but I found it impossible to get configured in an established environment with entrenched bash usage (which zsh, by the way, has no problem with)
Regarding $PATH: it is actually not delimited at all in fish. Instead, $PATH is an array, which is a first class notion in fish. This allows for nice tricks like, say, looping through $PATH:
for dir in $PATH
echo $dir
end
or deleting its last entry: set --erase PATH[-1]
Of course, fish flattens $PATH into a colon-delimited string when setting it as an environment variable, and unflattens it when reading it from the environment.export PATH=$PATH:<new_dir>
As for the larger question of environment configuration; we pull in a number of shell configuration scripts owned by the infrastructure teams. You are right, there is no universal way to set path due to things like "export" vs "setenv", but often multiple shells support the same syntax so you can sometimes use a config script meant for bash in zsh, for example. I had hoped that fish would be able to use csh scripts, because it shares "setenv", but csh of course delimits PATH with colons.
You say that PATH is treated as a colon-delimited string when accessed as an environment variable... Hmm. That wasn't what I was seeing, but it is entirely possible I made a mess of things, or that I broke things when I compiled it.
Anyway, it's unlikely I personally will be able to use fish. I hit many more obstacles than just PATH, but that was the easiest example and I thought I'd share some feedback.
https://github.com/fish-shell/fish-shell/issues/522 tracks having a bash compatibility layer - as you can see there's a lot of discussion!
jsoc_mach=`csh -f -c 'source /home/jsoc/.setJSOCenv && echo $JSOC_MACHINE'`
It could be abstracted farther.Still a pain point, though.
Where did you get that fish? And are there more animal characters?
I'm surprised I can copy it into other apps and it doesn't bug out.
🐟
Very cool.
$ time zsh -c "echo foo" foo
real 0m0.005s user 0m0.002s
https://news.ycombinator.com/item?id=3880280
path_helper turned out to be boning me pretty hard at home, these instructions were very helpful.
log-20120103
log-20120104
log-20120503
log-20120603
log-20120604
I can do: "$ less 603<tab>"And it will complete to: "$ less log-20120603"
I cannot recall whether I had to specifically enable this in zsh.
I'm going to give it a go regardless but wanted to know if there were pitfalls and what people have done to alleviate them.
[0] https://wiki.archlinux.org/index.php/Fish#Troubleshooting
The most annoying differences are the missing/changed special variables: POSIX has special $@/$* to return parameters: you have to use arrays for these in fish. POSIX puts exit status in $? and fish in $status; also $$ becomes %self, and there is no convenient way to expand to the PPID. Also annoying is the absence of "||" and "&&" operators.
Most of these differences, and why they were made, are explained in the manual.
$cmd1 && $cmd2 || $cmd3
becomes
$cmd1; and $cmd2; or $cmd3;
i.e., they're just commands that inspect $status and run their arguments.
$cmd1 || $cmd2 `$cmd3`
vs $cmd1; or $cmd2 `$cmd3`
If 'or' is 'just a command', I would think the shell would evaluate $cmd3 before calling $cmd2. Or are 'and' and 'or' built-ins that are similar to Lisp special forms/Forth immediate words?Edit: decided I wasn't that lazy today, and looked it up in the documentation. "and" and "or" are built-ins (http://fishshell.com/docs/2.0/commands.html#and, http://fishshell.com/docs/2.0/commands.html#or)
Also, URLs with & don't work in bash anyway. Or rather, they will work, but do something you wouldn't expect - it would ignore & and everything after it, and run command in the background.
Please note that zsh works similarly to fish. Well, mostly. It seems that zsh has special logic that automatically inserts backslash before ? if it detects an URL. Perhaps that could be implemented in fish. But it also feels somewhat magical. Why "\?" would appear when I type "?"? But perhaps it's the best way. In your case, it's possible to break it. But the break looks really contrived, so perhaps zsh behavior would be safe.
[glitchmr@pineapple tmp]$ mkdir -p https://news.ycombinator.com
[glitchmr@pineapple tmp]$ touch https://news.ycombinator.com/itemsid=5723235
[glitchmr@pineapple tmp]$ wget https://news.ycombinator.com/item?id=5723235
--2013-05-17 13:39:09-- https://news.ycombinator.com/itemsid=5723235
Resolving news.ycombinator.com (news.ycombinator.com)... 184.172.10.74
Connecting to news.ycombinator.com (news.ycombinator.com)|184.172.10.74|:443... connected.
HTTP request sent, awaiting response... 404 Not Found
2013-05-17 13:39:10 ERROR 404: Not Found.I reverted it back to bash and I get fish as my shell by spawning "urxvt -e fish" instead of "urxvt" (in my window manager configuration). This works well.
if status --is-interactive
set PATH ~/.local/bin /opt/local/bin $PATH
end
in your ~/.config/fish/config.fish file. Your other shells have the paths you want either because you configured them that way at some point, or because their global configs (e.g. /etc/bashrc) have broader paths. There's nothing magic going on here.It's not a deal-breaker, of course. If you become fluent in POSIX-shell you can translate between it and your custom shell, and things should be fine... but becoming fluent in two shells is a lot more work than becoming fluent in one shell.
If you never need to interact with other people's machines, and other people never have to interact with yours, then sure, go nuts and install whatever shell you want.
$ bash
And hey presto, back in bash land.I agree that it makes sense to know the lowest common denominator well before you go after something better—especially as you'll know straight away if and why it's "better".
Slightly OT, but I honestly think that "community best of" projects like oh-my-zss and the Vim ones actually do people a disservice since they are not zsh or Vim, but rather someone's opinionated, non-standard version of them.
The annoying case is vim plugins that use $SHELL to execute some bash/sh code. The workaround is to specify `set shell=sh` in .vimrc. We did not attempt to address this in fish (I didn't check but I would guess that tcsh is affected the same way).
The critical case is, at the login window, OpenSUSE invokes the login shell with a POSIX-ism (specifically 'exec "${@}"'), which was not recognized by fish. So setting fish as your login shell would lock OpenSUSE users out of their machines entirely!
What we did was hack fish to recognize exactly this command in its arguments, and handle it the way OpenSUSE expects, via a new function "fish_xdm_login_hack_hack_hack_hack". Heh.
I also don't like the implementation of the prompt text as a function. It's the first thing I wanted to customize, and it looks like I need to copy and paste the existing definition of fish_prompt and hack it into shape. There's no built-in equivalent of \$, so you need to find out if you're root and do it yourself. And the existing check just does it with a string compare of $USER with 'root', rather than euid==0.
Hacking preferences in like this isn't a problem to begin with. The real problem comes down the road, when the defaults change and improve, and you now have to be concerned with merging your customizations with the new and improved stuff.
to edit the default prompt (or any function):
funced fish_prompt
will launch your editor. then: funcsave fish_prompt
to persist a copy in your user's configuration.all shell instances will pick it up right away, no need to close, relaunch or source anything.
And how to incrementally search the history (i.e. anywhere in the command, not just the start of the line like the autocomplete)?
And does fish really need to separate out its subshell from text substitution? E.g. I'd write 'echo "my host is $(hostname)."' in bash, but in fish I seem to need to use 'echo "my host is " (hostname) "."', which is a lot more fiddly, noisy, ugly etc.
And do you know the equivalent of <() in bash? I use that with fgrep -f a lot. And (<todo.txt)? That's another one I use in workflows, though (cat todo.txt) would be a verbose alternative.
I believe Alt+. (or any kind of history substitution) hasn't been implemented by design. I don't have references handy but they should be easy to find.
Incremental history search is just type something and then up arrow.
The rest of your questions I don't know the answers but it wouldn't surprise me if there were none. Fish prefers to have a simple and coherent syntax to a concise one (though I agree the text substitution is annoying – it seems they usually put the subshell result in a variable and expand that in the string).
This helps understanding their design goals http://ridiculousfish.com/shell/user_doc/html/design.html
Incremental search isn't too bad once I found out about bind and the other key bindings, as the arrow keys are some distance from the home keys.
Lack of Alt+. quickly became annoying. It's so useful; meanwhile, prefix search isn't a significant improvement over incremental search, and I usually know ahead of time whether my command is in the history or not, so being prompted an irrelevance is more annoying than having to type Ctrl+R in readline. I disable auto-completion in browsers, Google etc. for similar reasons.
You're right about not much else. Command substitution is the only thing implemented, not subshells or process substitution. I probably exercise my shell more than average, so I don't think fish is feature-rich enough yet for me.
It's a good thing the design goals have been updated to remove "a large performance decrease [...] is acceptable in order to improve [modularity]". That would have been a total killer. Process forking is often a performance limitation for me in the shell, so I strive, wherever possible, to use the builtins that fish so proudly spurned.
echo my host is (hostname).
Doesn't need quotes.($cmd | psub)
I miss incremental history search myself -- that's probably my most used bash feature. Typing a few letters and then hitting C-P or up arrow works, but there's no way to refine the search if you don't get the result you're looking for.
I haven't installed it yet, but it sounds like the same information is in both places. Given its dependency on doxygen, I think it's very likely.
Regarding customizing your prompt, try running 'fish_config' and check list of already available prompts from prompts tab.
Autocompletion - a feature I generally don't use in other contexts - and reduced functionality seem to be its main USPs. With readline, process substitution and subshells (for ad-hoc fork/join jobs started from the command line) it might be competitive with other shells.
For example, a reasonably common pattern for me, on the command line, is:
$ for d in *; do
test -d "$d" || continue
(
cd "$d"
time-consuming-task-1
time-consuming-task-2
) &
done
I don't think I could do this in fish today without writing a script, as it doesn't have subshells and can't run functions in the background.There's also a big advantage in having the shell be the same (or highly similar) to your preferred ad-hoc scripting language. It means you can retrieve complex commands from your history and paste them into the script, with only a slight cleanup to parameterize them. A whole complex operation can be spiked and tested interactively before being put together into something reusable - possibly without foreknowledge that the task is going to be that tedious, or needs to be encapsulated. Zsh looks like a better alternative to bash for these reasons.
for d in *
test -d $d
or continue
begin
cd $d
time-consuming-task-1
time-consuming-task-2
end &
end
However it errors; seems you can't do `end &`. Probably a bug; I'll report it. When fixed, I imagine we could actually do it even better with fish: for d in *
if test -d $d
cd $d
time-consuming-task-1
time-consuming-task-2
end &
endHaving said that, `enc &` erroring is indeed a bug, expected behavior would be to run the `begin ... end &` block in the foreground anyway.
[1]: http://www.hanselman.com/blog/Console2ABetterWindowsCommandP...
You seem to be confusing terminals (programs that provide a text environment) and shells (usually text-based, often run inside a terminal). Mintty is a terminal. cmd.exe is a shell, but will spawn Windows' own ANSI terminal when asked. Cygwin's bash will also spawn Windows' own terminal when run without one. Fish is a shell, and needs to be run inside a terminal.
Console2 is different again. As I understand it, it wraps Windows' terminal, providing some extra features.
If you install the Powershell Community Extensions (PSCX), a pretty useful Powershell module in general, it has a command (Invoke-BatchFile) to execute a batch file and propagate the environment changes back to powershell. (While this is not always sufficient; I have found it to be enough for most purposes)
http://en.wikipedia.org/wiki/Windows_PowerShell
It's actually got some quite interesting concepts, and is extremely consistent. These tips also convey the approach and how it works:
Every command is of the form Verb-Noun. Which means you can get off the ground really quickly, as there are only about 15 different verbs. This means you can often guess what you want, even for commands you've never used. Still can't find what you want? Then you can use wildcard searching on the Get-Command command, which returns all matching commands!
The icing on the cake for me is the consistency between interacting with different data sets. For example, New-Item is a command for creating a new item (duh!). The great thing about this however is that this command can be used to create files, registry entries, websites in IIS. This works by allowing you to browse all these things just as you would a file system. e.g. you can "cd" into IIS and treat it just like you would files on disk.
Really an eye opener into what a modern shell should be like
Sounds quite a lot like VMS' DCL, which is similarly intuitive, albeit overly verbose at times.
If you dislike using it directly through cmd.exe due to the abysmal UI (as I do), there's alternatives that let you use it with putty[2] and leave cmd.exe interface all together.
[1] http://stackoverflow.com/questions/573623/powershell-vs-unix...
EDIT: I meant mintty .. it is small, pretty and configurable.
Linux is much faster, primarily down to how reliant the Unix way is on forking and how much work Cygwin need to do to emulate that on Windows, but it's only noticeable when working with a lot of data that spawns O(n) processes.
Such scripts can often be rewritten as shell pipelines that don't scale in the same way. E.g. instead of running grep once per file, do xargs grep and filter by filename prefix if necessary; or instead of running mv once per file for renaming multiple files, convert to equivalent CMD syntax and output to a temporary batch file, and run the batch file.
I've got a number of scripts like these, implemented once for the Unix way, and again for Cygwin. But they don't come up all that often, and I haven't had to write one in years.
You can do stuff like
ps | ? { $_.Name -match "iexplore" } | % { $_.Kill() }
to kill all instances of internet explorer. The `ps` command outputs System.IO.Process objects. The ? { ... } syntax is a filter, inside which you can use $_ to refer to the element you're matching. You can access the 'Name' property directly and use -match to match it against an expression. Finally the % { ... } syntax executes some code on every element, in this case it calls System.IO.Process.Kill() to kill the process.Console2 puts a nice face on things and supports tabbing and resizing, as you would expect from a usable terminal window.
Thinking back on it I'm not terribly surprised this happened given what Console2 is.
I was working with this configuration for some time and it is really nice if you're satisfied with life inside MS's walled garden. The problem is that there is absolutely no interoperability with standard *nix tools. What's worse, PowerShell pretends that there is - `ps` in your example is just an alias for 'Get-Process' cmdlet, the same is true for cat, ls and other things.
Aside from that PowerShell is really solid shell. You can extend it with C# code and you get access to many .NET feature both in the command prompt and from PowerShell scripts. The scripts are quite nice for a shell scripts, it offers a few built-in data structures like arrays and hashes, there is a quite good autocompletion, even for .NET classes and objects and so on.
- msys-git (I have ls, rm -rf... all unix goodness)
- clink (better tab completion, history, all around good stuff)
- console2 (styling)
- ansicolor (colored prompt)
and also I got some usefull aliases. If you are interested I can write down some steps for other people to follow.
screenshot http://i.imgur.com/hATwCVI.png
Perhaps to be files all the way up is a limitation of the bazaar - at least until one hits the JVM, hopefully. There's no contract assuring that level of abstraction between the user and the turtles. And agreement that such a layer of abstraction is a good thing is unlikely to be forthcoming.
It has tab autocompletion. You can send commands directly to the underlying system shell with '!' (e.g., !dir) and save the result in a Python variable for manipulation (a = !dir). It has special commands called "magics" that let you do neat stuff that the standard shell doesn't, like time how long things take to run. It has a robust command history.
What this means is you can write Python code as your shell scripting language.
use this URL: https://raw.github.com/ridiculousfish/homebrew/9a481458491b6...
Really, this 100x better than bash.
1. download and install[0]
2. read the tutorial[1]
3. ...
4. profit
[0]: http://fishshell.com/#platform_tabsThat said, the new version is just ace! I gave it 30 minutes and it basically does everything I do with zsh right now. All that with about 5% of the configuration effort I put into zsh. Plus, it's so much faster than zsh.
I'll give fish a go as my main shell. Let's see were this goes.
_J""-.
.-""L_ /o ) \ ,';
;`, / ( o\ \ ,' ; /
\ ; `, / "-.__.'"\_;
;_/"`.__.-"Which to go for..?
. bin/activate.fishEven better is Virtualfish, which I've been using and contributing to very happily: https://github.com/adambrenecki/virtualfish
FWIW my (rapidly changing) fish configuration:
https://github.com/ithinkihaveacat/dotfiles/tree/master/fish
It works by getting notification when the PWD environment variable changes, which seems like an elegant way of managing this.
[1] http://serverfault.com/questions/164305/how-can-i-set-enviro...
Also, why are you changing your EDITOR on a one-off basis, that shit should be permanent.
BTW, My point is not specific the EDITOR variable.
From the current docs:
A universal variable is a variable whose value is shared across all instances of fish, now and in the future - even after a reboot. You can make a variable universal with set -U:
> set -U EDITOR vim
Now in another shell:
> echo $EDITOR vim
I am not asking for a way to make a variable universal, I am looking for a way to specify variable per command.
https://github.com/fish-shell/fish-shell/issues/587
I use Rails with rbenv, a common package which adds shell commands to control which version of Ruby is used. There is a fish port of it, so when you run the very common command "rake" it invokes a fish function which sets up the right environment. And when you do run rake, you often need to set environment variables to set one-time options for the procedure you're invoking.
Now the trap is set for the would-be fish user. Because you're actually using the fish shell to customize a command, you can't just punt to env with "env VERSION=20130411222645 rake db:migrate:down" because you actually want to run the fish function, not an executable.
So for now, I'm setting environment variables at the command line and unsetting them afterwards. It's really getting old, especially because it loses context in my command history. I think I'll probably ditch fish if I can't find a workaround for this, so any suggestions are appreciated.
- Anything that shells out using your default shell seems to assume a bourne-compatible shell. I remember this biting me when using various emacs commands that assumed all the world is a bourne shell.
- Copypasting commands is annoying too, but I've been evaluating zsh for the past few months and i've been bitten there too...seems like anything that isn't bash will run into that issue, and you can always just use bash for those instances.
- Virtualenv comes with a fish shell script, but last I checked it didn't actually work.
- Does fish still throw a hissy fit every time you try and tab-complete a command and your $PATH has a non-existant path in it?
Other than that fish looks really polished and I plan on devoting a few days to it to give it a fair shake.
One of the nice features of autosuggestions is that they remember which arguments were files, and which ones were not. So if you have changed directories, !vi will edit a file that does not exist - probably not what you meant to do. The fish autosuggestion won't suggest it at all.
Other examples of projects officially on OFTC include: debian, tor, open street map, libvirt/qemu and related tech, ceph, awesomewm, gcc, smuxi... So fish isn't all alone there.
There are also projects that operate their own networks, such as GNOME and Mozilla.
Bash: shopt -s autocd
Zsh: setopt autocd
And as others have also said, fish knows nothing of your bash history. It'll work fine with quake; use chsh to change shell for your user.
its annoying having
Welcome to fish, the friendly interactive shell Type help for instructions on how to use fish
come up all the time
set fish_greeting-e to erase