Start zsh with a custom zshrc

From the man pages:

STARTUP/SHUTDOWN FILES
       Commands are first read from /etc/zshenv; this cannot be overridden.  Subsequent  be‐
       haviour is modified by the RCS and GLOBAL_RCS options; the former affects all startup
       files, while the second only affects global startup files (those shown here  with  an
       path starting with a /).  If one of the options is unset at any point, any subsequent
       startup file(s) of the corresponding type will not be read.  It is also possible  for
       a  file  in  $ZDOTDIR  to  re-enable  GLOBAL_RCS.  Both RCS and GLOBAL_RCS are set by
       default.

       Commands are then read from $ZDOTDIR/.zshenv.  If the shell is a  login  shell,  com‐
       mands are read from /etc/zprofile and then $ZDOTDIR/.zprofile.  Then, if the shell is
       interactive, commands are read from /etc/zshrc and then $ZDOTDIR/.zshrc.  Finally, if
       the shell is a login shell, /etc/zlogin and $ZDOTDIR/.zlogin are read.

       When a login shell exits, the files $ZDOTDIR/.zlogout and then /etc/zlogout are read.
       This happens with either an explicit exit via the exit  or  logout  commands,  or  an
       implicit exit by reading end-of-file from the terminal.  However, if the shell termi‐
       nates due to exec'ing another process, the logout files are not read.  These are also
       affected  by  the  RCS and GLOBAL_RCS options.  Note also that the RCS option affects
       the saving of history files, i.e. if RCS is unset when the shell  exits,  no  history
       file will be saved.

       If  ZDOTDIR  is unset, HOME is used instead.  Files listed above as being in /etc may
       be in another directory, depending on the installation.

       As /etc/zshenv is run for all instances of zsh, it is important that it  be  kept  as
       small  as  possible.  In particular, it is a good idea to put code that does not need
       to be run for every single shell behind a test of the form `if [[  -o  rcs  ]];  then
       ...' so that it will not be executed when zsh is invoked with the `-f' option.

so you should be able to set the environment variable ZDOTDIR to a new directory to get zsh to look for a different set of dotfiles.

As the man page suggests, RCS and GLOBAL_RCS are not paths to rc files, as you are attempting to use them, but rather options you can enable or disable. So, for instance, the flag --rcs will enable the RCS option, causing zsh to read from rc files. You can use the following command-line flags to zsh to enable or disable RCS or GLOBAL_RCS:

  --globalrcs
  --rcs
  -d    equivalent to --no-globalrcs
  -f    equivalent to --no-rcs

To answer your other question:

is it possible to start zsh, run "source /path/to/file", then stay in the same zsh session?

Yes, this is pretty easy according to the above directions. Just run zsh -d -f and then source /path/to/zshrc.


while with ZDOTDIR, you can tell zsh to interpret a file called .zshrc in any directory of your choosing, having it interpret any file of your choosing (not necessarily called .zshrc) proves quite difficult.

In sh or ksh emulation, zsh evaluates $ENV; so you could add emulate zsh at the top of your /path/to/file and do:

ssh -t host 'zsh -c "ARGV0=sh ENV=/path/to/file exec zsh"'

Another very convoluted approach could be:

ssh -t host 'PS1='\''${${functions[zsh_directory_name]::="
    set +o promptsubst
    unset -f zsh_directory_name
    unset PS1
    . /path/to/file
 "}+}${(D):-}${PS1=%m%# }'\' exec zsh -o promptsubst -f

That one deserves a bit of an explanation.

${foo::=value} is a variable expansion that actually sets $foo. $functions is a special associative array that maps function names to their definitions.

With the promptsubst option, variables in $PS1 are expanded. So, upon the first prompt, the variables in that PS1 will be expanded.

The zsh_directory_name function is a special function that helps expanding the ~foo to /path/to/something and the reverse. That's used for instance with %~ in the prompt so that if the current directory is /opt/myproj/proj/x you can display it as ~proj:x by having zsh_directory_name do the mapping proj:x <=> /opt/myproj/proj/x. That's also used by the D parameter expansion flag. So if one expands ${(D)somevar}, that zsh_directory_name function will be called.

Here, we're using ${(D):-}, ${:-}, that is ${no_var:-nothing} expands to nothing if $no_var is empty, so ${(D):-} expands to nothing while calling zsh_directory_name. zsh_directory_name has previously been defined as:

zsh_directory_name() {
  set +o promptsubst
  unset -f zsh_directory_name
  unset PS1; . /path/to/file
}

That is, upon the first PS1 expansion (upon the first prompt), ${(D):-} will cause the promptsubst option to be unset (to cancel the -o promptsubst), zsh_directory_name() to be undefined (as we want to run it only once) $PS1 to be unset, and /path/to/file to be sourced.

${PS1=%m%# } expands (and assigns $PS1) to %m%# unless PS1 was already defined (for instance by /path/to/file after the unset), and %m%# happens to be the default value of PS1.