I want to be able to start zsh with a custom rc file similar to the command: bash --rc-file /path/to/file

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

Note: The command zsh --rcs /path/to/file does not work, at least not for me...

EDIT: In its entirety I wish to be able to do the following: ssh to a remote server "example.com", run zsh, source my configuration located at /path/to/file, all in 1 command. This is where I've struggled, especially because I'd rather not write over any configuration files on the remote machine.

  • 1
    Hi Katz, welcome to unix.SE. I've edited your question to add some formatting that makes it (slightly) easier to read. You can click "edit" to see how it works. I've also removed some extra things, like "Thank you" and your signature (all posts on the Stack Exchange network are automatically signed). – drs May 23 '14 at 19:39
  • 1
    Thank you, I've now learned how to type code as such! – hjkatz May 23 '14 at 20:19

From the man pages:

       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

       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:

  -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.

| improve this answer | |
  • As this does work per my question, I failed to mention that I can only run 1 command. This does not satisfy what I wish to use this for (a custom ssh with my personal configurations). The problem lies in that running zsh -d -f; source /path/to/file does not ever execute the second command in the first session of zsh until exiting. – hjkatz May 23 '14 at 20:13
  • In its entirety I wish to be able to do the following. ssh to a remote server "example.com", run zsh, source my configuration located at /path/to/file, all in 1 command. This is where I've struggled, especially because I'd rather not write over any configuration files on the remote machine. Thank you for you answer though! – hjkatz May 23 '14 at 20:16
  • 1
    seems like your problem is not in using a custom zshrc but in not knowing how to use a shell over ssh. If you run ssh host "zsh -d -f; source /path/to/file", then ssh will run first zsh on the remote host, then source ... after the zsh shell exits. Instead what you want to do is ssh -t host zsh -d -f to drop into an interactive shell on the remote host, or if you don't want an interactive shell, do ssh host zsh -d -f -c \"source /path/to/file\; other command\; ... \". – jayhendren May 23 '14 at 21:01
  • No I understand how ssh works with interactive shells. The problem is that running ssh -t host "zsh -d -f; source /path/to/file drops me into an interactive (and barren) zsh shell. – hjkatz May 23 '14 at 21:45
  • 1
    I already told you why this is and how to fix it. When you run ssh -t host "zsh -d -f; source /path/to/file", the command source... is NOT run inside the zsh shell. It's run in your login shell after the zsh shell exits. To test this out, run ssh host "zsh; echo foo". You will see the output "foo" after you exit from the zsh shell. – jayhendren May 23 '14 at 22:32

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.

| improve this answer | |
  • 1
    This looks quite extravagant and I will give it a try as soon as possible. I'm hopeful this works! – hjkatz May 23 '14 at 21:46
  • The emulate trick is cool and simple. Hope it does not have any side effects – balki Oct 8 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.