Search code examples
environment-variablesfish

Local variables implementation


I've been using the fish shell for a bit now, and I've recently had a conversation with a coworker over local variables. Apparently, Bash doesn't support local variables, and only uses environment variables to communicate dynamic data between processes. Are local variables also just environment variables, but with something extra? I'm curious as to how fish has created this behavior.


Solution

  • Bash doesn't support local variables

    That's not true. Bash (and other shells including dash - it's one of the few POSIX extensions it has) have the local keyword to create local variables. They just default to global, while fish defaults to local.

    Also when you say "environment variables" what you mean are "exported" variables, which require an explicit "export" step in posixy shells, and the "-x" or "--export" flag to set in fish.

    I e. there are two different things at play here - whether this variable is available just in this function/block/whatever, and not the outside, and whether it is passed on to children, including external processes.

    Are local variables also just environment variables, but with something extra?

    Non-exported variables are something less. They aren't given to the OS's setenv function, so it doesn't copy them to child processes.

    Local variables are removed when the block ends. In practice this can be done nicely by putting them on a stack and "popping" the top.

    Note that, in fish at least, these concepts are entirely orthogonal:

    You can have local-exported variables (with set -lx), and they'll be passed to external commands and copied to functions (so they get their own local version of it), but removed when the function ends. These are useful to change something temporary - e.g. to set $PATH just for a function, or to override $EDITOR when calling something.

    And you can have global-unexported variables, which can be accessed by functions but not external commands. These are useful for shell settings like $fish_function_path, which isn't useful to external tools, or $COLUMN, which might even break external tools if exported (because they start to read it instead of checking the terminal size themselves).