0

My login shell is zsh. I have added the following two lines to my .zprofile file:

path+=$HOME/foobar123
alias foo='echo bar'

Then, if I switch to bash or fish, by typing bash or fish and pressing Return, echo $PATH will continue to show me the foobar123 part, but the foo alias won't work.

Why is that? Why aliases and path modifications are treated differently?

5
  • 1
    you could write a .aliases file with your aliases and source it from the different shell rc files Commented Dec 18, 2024 at 19:31
  • 1
    @Fravadona argh! Yes, you're quite right of course. I was being stupid and forgot to take into account that I set my PATH in my ~/.bashrc so the exported value was being overwritten when I switched shells. My bad, thanks. Commented Dec 18, 2024 at 19:40
  • @Fravadona "typing bash should keep the current exported environment variables" - But I didn't use export, I used just path+=..., right? Commented Dec 18, 2024 at 19:43
  • 1
    @jsx97 path+=... is kind of converted to PATH=$PATH:... automatically; and PATH is exported by default by every shell, I think Commented Dec 18, 2024 at 19:50
  • 2
    This question is similar to: How to make alias work in other terminals. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Dec 18, 2024 at 20:18

1 Answer 1

4

path is the shell array variable that is tied to the PATH shell variable which is itself tied to the PATH environment variable.

When executing a command, all the memory of a process is wiped.

Environment variables are a way to pass data across execution. Like the command arguments, they are a list of NUL-delimited strings, but contrary to arguments, by convention:

  • they take the form of VAR=values
  • commands (whether they're shells or anything else) remember the list of environment variable they received when they were executed, and pass them along to the commands they execute if they or their children do, so as to implement a form of inherited and inheritable environment. There is a standard C API (putenv(), setenv(), unsetenv(), environ variable) to maintain that list of remembered env vars (the environ), and to execute commands, passing that list along (execl(), execvp()... which are wrappers around the execve() system call).

Shells specifically, in addition to doing that make up a variable in their language for some of the environment variables they receive and whose name is compatible with that of a shell variable. And the Bourne-like ones can promote a shell variable to an environment variable with the export builtin (other shells have equivalents).

csh, tcsh, zsh, yash, fish shells have ways to tie $PATH or other variables with :-separated values (generally environment ones such as PATH) to array variables.

For comparison, perl (also a programming language interpreter, but not a shell one) maps environment variables to its %ENV associative arrays (for example, the PATH environment variable is available in $ENV{PATH}), awk same with ENVIRON["PATH"], vim has $var for environment variables while it's just var for its own variables or @x for registers, etc.

To sum-up, environment variables, such as PATH are something that is universal and understood by everything and inherited (by convention) across execution.

There is no equivalent for shell aliases, which is a (poor) feature of some shells (not all) initially from csh, whose syntax varies from shell to shell, nor other data structures of any language.

Some shells such as rc and derivatives or bash can export their own function (also arrays in rc and derivatives), and to do that, they hijack environment variables, where the function definition is stored in a specific format, but only other instances of the same shell can load those variables from the environment and recreate the functions (or arrays) they encoded. Those variables don't make sense to other shells (or perl, vim, awk...) whose syntax is different anyway.

To be able to pass your list of zsh aliases to bash so equivalent bash aliases be created, you'd need to create code in the bash language which once evaluated would recreate those aliases. bash and zsh have some syntax in common, in particular the basic alias builtin syntax was copied in both from the Korn shell rather than csh, but zsh has added more features such as global aliases or suffix aliases and doesn't have the same limitations as bash when it comes to alias names, and bash ones can contain NULs in neither name nor value, so not all zsh aliases can be converted to bash aliases.

The quoting syntax is also different between the two shells, though they understand single quoting the same way (as long as rcquotes is not enabled in zsh). zsh makes the list of its plain aliases available in the $aliases special associative array, and like bash can dump a list of alias definitions with alias -L.

But in the latter, it does not always use single quoting, and could dump aliases whose name or values wouldn't work in bash, so you'd be better of looping over $aliases, filter out those that can't work in bash and do the quoting by hand (like with the qq parameter expansion flag).

5
  • "There is no equivalent for shell aliases, which is a (poor) feature of some shells" - You mean that using aliases is generally a bad practice? Commented Dec 18, 2024 at 20:31
  • 2
    They have their uses like C preprocessor macros (to which they're very similar), but you have to understand that it's just text replacement before re-evaluation and the (many) limitations it entails. They ended up being popular because they first appeared in csh, which was popular at the time (80s) and didn't have (and still doesn't have) functions. Commented Dec 18, 2024 at 20:33
  • I use the following Tor script (to bypass web censorship in my country): github.com/gravmatt/easy-tor. To enable Tor, the following line is used: alias tor_on='sudo networksetup setsocksfirewallproxy "Wi-Fi" 127.0.0.1 9050 && tor'. How would you suggest to change it to get rid of alias? Commented Dec 18, 2024 at 20:46
  • 1
    Yes, use a script or function for that. If you do tor_on 2> /dev/null for instance, only tor's errors are redirected, because that's not defining a tor_on command that runs both sudo and tor commands, but just expanding to sudo networksetup setsocksfirewallproxy "Wi-Fi" 127.0.0.1 9050 && tor 2> /dev/null which is re-evaluated as code where the 2> /dev/null applies to tor only. Commented Dec 18, 2024 at 21:03
  • 1
    @jsx97 I don't think Stéphane is arguing that you should never use aliases. My understanding is that he is pointing out that aliases are a poorly designed feature and very limited in what they can do since they just replace text before executing the result. Functions are far more versatile, no question about that, but I don't think anyone would say there is anything wrong with using basic aliases like alias l='ls-l' (and please correct me if I've misunderstood you, Stéphane). Commented Dec 19, 2024 at 10:11

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.