Tried fish a couple of times, it's really good, many zsh plugins are created to replicate features of fish. But it's not my default shell, because I need to run bash shell scripts and I didn't find any way to do it in fish. So I am stuck with my slow zsh.
I often see people complain about this but I seriously don't understand. The shebang at the top of a bash script will point to bash no matter what your shell is.
At various jobs I've often seen bash scripts to set up your environment (mostly environment variables). Running a bash script with shebang will not preserve the changes to the environment variables, will it? At least that was my experience.
I use xonsh and fortunately it has source-bash for stuff like that.
Yeah I would have thought so too, but I have personally ran into this issue running fish-shell on my mac. There are some scripts I need to run that do not work even when I shebang the script to run in bash.
Yes, it really is odd, I couldn't figure it out so switched back to zsh.
The specific issue was to do with a script we had to run to gain ssh access to an internal network. I can't post the script, but it was related to openssh.
Even logging into bash and running the script didn't work, I had to remove all fish binaries, symlinks, etc and set my shell to bash/zsh. Maybe it was an issue with how I installed fish, but yeah like I said, very strange, but I can vouch that I've encountered a similar issue before
It's a real shame because I think the fish syntax alone is worth the switch, for my personal machine(s) I use it.
Edit: this was years ago now, about 4 years, maybe the issue doesn't exist anymore but it caused me a bit of grief at the time (beacuse I didn't know it was related to using fish!), I've not since tried it again. I might try again and get back to this thread
Most likely a command in your script (or one source-d into it) makes an assumption about your $SHELL or login shell that is true for bash/zsh but not for fish.
See my other comment and let me know if that script contains
ssh-agent $SHELL ...
or
exec $SHELL ...
or
eval "$SHELL ..."
or similar. :)
If it ends up passing a script file or arguments to $SHELL and you wanna fix it without rewriting it, just add some conditionals where $SHELL is used and use the equivalent flags or syntax when $SHELL indicates fish.
Alternatively, if you just wanna work around it, just launch that script like
fish doesn't have builtins but all fish commands are external binaries or fish functions. i think at one point early in the history of fish those binaries may have been installed on the global path so they were accessible outside of fish and possibly there was a name conflict with one of them that this script triggered.
although such a name conflict should not have happened (and i can't think of which command such a script might have used that would also be a fish command), and the global path thing was also fixed soonish. but this is all a faint memory, so i am not sure i remember any of that right.
- cd
- source, .
- eval
- string
- and
- or
- builtin
- command
and many others.
Not sure what the point of distinguishing between fish builtins and fish functions is; whether a builtin is shipped as a function distributed with fish or a reserved word in the fish evaluator seems like an implementation detail.
fish has grown and evolved. i was referring to this:
Builtin commands should only be created when it cannot be avoided. echo, kill, printf and time are among the commands that fish does not implement internally since they can be provided as external commands. Several other commands that are commonly implemented as builtins and can not be implemented as external commands, including type, vared, pushd and popd are implemented as shellscript functions in fish.
if i remember correctly, this led to some useful commands that are builtin elsewhere to be external binaries shipped with fish. but since those where not actually tied to the fish shell they could run without it, and if they ended up on the global path be accessible from other shells.
the relevant text on the website has been changed, but it is referenced here:
If you wanna add a builtin like that to your own distribution of fish, you could do it cleanly by keeping those binaries in /usr/lib or /usr/libexec and then wrapping them in a fish function that ships in fish's install prefix. (This is basically how fish's Python scripts for generating completions from manpages are shipped today.)
This is plausible if you have scripts that do dumb shit like
eval "$SHELL ..."
because (at least sometimes?) $SHELL is set by your login program and not your shell, and dropping to an alternative shell by just typing
zsh
and hitting enter or whatever won't reset $SHELL.
You mention elsewhere that this had to do with a special OpenSSH setup, which also fits.
One of the things you can do with ssh-agent is use it to launch a child process with a dedicated SSH agent that (only) has certain keys on it, and which exits once its child exits. This is sometimes handy for deployment scripts or doing git checkouts or whatever because you can ensure you don't get locked out for too many auth attempts because the user just has too many extraneous keys on the agent associated with their normal user session.
If you were leveraging this feature for interactive shells, you might be tempted to use $SHELL to decide what executable to have ssh-agent launch, so that you could (for example) accommodate both bash and zsh users and let them launch a shell with a special SSH agent but which honors their usual preferences by loading their usual shell and reading their usual zshenv or bashrc or whatever it is.
You mention as well that you had to actually uninstall fish to get things to work again, and also that you were on macOS. I can't be certain about the cause here, but one obvious thing occurs to me:
macOS doesn't handle environment setup like any 'normal' (Linux or *BSD) Unix. On normal Unices, your login shell actually also launches your graphical user session, so to configure a session-wide environment variable, you just set it in your shell startup somewhere. On macOS, login shells are actually only used in SSH sessions and terminal emulators. If you want to set environment variables for apps that are not launched from terminal emulators, you have to use hacks (like Doom Emacs' env file, for example) or configure them for the whole user session via a LaunchAgent.
In the case of $SHELL, that environment variable is used by editors to determine what shell to use when you run external commands. Without it, if you are a fish user and you launch MacVim or Emacs (or, presumably, VSCode or anything else) from your dock, when you go to launch external commands, they will run not in fish but some other shell (probably zsh or bash). If your install method for fish tried to handle this for you (pkgsrc and Nix don't, but the .pkg from the developers or Homebrew might, idk), or if you dropped to bash only from terminal emulator windows that were already running fish instead of opening a new session for bash, you may have wound up in a bash session where $SHELL was still set to fish. That's the only reason I can think of for why you might have had to actually uninstall fish to get this ill-behaved script to work right.
Anyway:
1. As a user, pay attention to what $SHELL is.
2. As a script author, never use `eval "$SHELL ..." or equivalent`.
> macOS doesn't handle environment setup like any 'normal' (Linux or *BSD) Unix. On normal Unices, your login shell actually also launches your graphical user session, so to configure a session-wide environment variable, you just set it in your shell startup somewhere.
That's no longer true for Linux, at least. GDM launches stuff via systemd user sessions, which do not source your profile.
I'm not sure how I feel about it. The old way feels 'simple' to me, but the new way does mean that shell misconfiguration won't hose your GUI sessions.
You don't have to translate them. Just stick `#!/usr/bin/env bash` on top. It is totally fine to use fish as your "terminal shell" and default to Bash for scripting for things like automation, etc. I've been doing this for a decade. I will also add that Fish is so good by default that I barely have any config.
Is the issue running bash shell scripts or copy-pasting one liners? If the latter, you can always use the command flag for bash to execute one liners within its own context.
bash -c "grep word file.txt | sort -u | tail"
Scripts shouldn't be an issue as long as you either launch it with the proper shell or configure the shebang correctly after making the script executable.
What do you mean? If the script is using hashbang, you can just run it. If not, run "bash script.sh". If you need to source it, use the plugin "bass". If you want to run a one-time bash command copypasted from somewhere, just type "bash", run your command, and then ctrl-c.
I asked an LLM to translate a bash script to fish once and it just changed the shebang line... cracked me up.
Edited to add:
There's a program out there for translating bash to fish called babelfish. It's pretty good but not complete, so it won't work for all scripts. Worth checking out, though: