2

I recently started using the Fish shell.

echo $EDITOR returns vim

But yet, when using programs that need to launch an editor and look for it in the EDITOR environment variable they don't seem to find anything.

As an example when using pass edit (from https://www.passwordstore.org/) it returns

vi: command not found (it uses vi as a fallback when nothing is set in the EDITOR env variable)

What did I miss?

2
  • 1
    I'm unaccustomed to the fish shell, but in most sh-like shells, you would need to export a shell variable for it to be accessible as an environment variable in child processes (or use setenv in csh). It's possible that the EDITOR variable that you have is just a shell variable and not an enviroment variable. I don't know what the equivalent of export in the fish shell is though.
    – Kusalananda
    Commented Jun 28, 2022 at 18:35
  • 1
    In fish, it's set -x EDITOR Commented Jun 28, 2022 at 19:30

1 Answer 1

8

Note that a few programs look for the $VISUAL environment variable before the $EDITOR environment variable, so if you have both set, $VISUAL will take precedence.

Also note that shell variables are just that, variables in the shell language. You'd need to call commands with EDITOR=preferred-editor in their environment for them to pick it up.

Shells can map some of their variables to environment variables that are then passed as var=value in the environment of all the commands they execute. In rc-like shells, that's done for all shell variables, in Bourne-like shells, that's done with export var. In csh, you use setenv var value to set an environment variable. In fish, you use the -x option of set:

> set var value
> echo $var
value
> printenv var
>

A $var shell variable was set, but not exported (as var=value) to the environment passed to printenv.

> set -x var value2
> echo $var
value2
> printenv var
value2

This time, printenv did get a var=value2 in the environment it received.

printenv is not a standard command but is commonly available. env is a standard command, so if your system doesn't have printenv, you could try:

env | grep -E '^(VISUAL|EDITOR)='

Though it could be fooled if you had variables with values such as var=<newline>VISUAL= or values larger than LINE_MAX.

Other options could be:

perl -le 'print $ENV{VISUAL}'
python -c 'import os; print(os.getenv("VISUAL"))'

Also note that though it is highly unlikely to be the case here, it is possible to execute a command with more than one var=value for a given var in their environment.

For instance, you could do

execve("/path/to/cmd", ["cmd", "some arg"], ["VISUAL=vi", "VISUAL=emacs"])

What value cmd will consider the VISUAL environment variable as having will depend on how they scan that env var list they received upon exceve(). You'll find that some commands / libraries (like libc's getenv()) will pick the first while some will pick the last. Some shells will map one of them to their corresponding env var but may leave the other one around and passed along in further executions.

So you could be doing set -x VISUAL vim, and printenv seeing emacs because fish was executed with both VISUAL=vi and VISUAL=emacs and only modified the first VISUAL whilst printenv gives you the second.

For this kind of thing to happen though, you'd need something or someone actively trying to trick you, and after double checking, it seems fish is one of those shells that do remove the duplicates from the environment if any.

1
  • Thanks very much for this detailed answer. Not only does it work, but I also understand why now. Yay!
    – bastian
    Commented Jun 29, 2022 at 8:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .