Start zsh with a custom zshrc
Solution 1
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
.
Solution 2
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
.
Related videos on Youtube
Comments
-
hjkatz over 1 year
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", runzsh
,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.-
drs almost 10 yearsHi 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).
-
hjkatz almost 10 yearsThank you, I've now learned how to type
code as such
!
-
-
jayhendren almost 10 yearsseems 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 firstzsh
on the remote host, thensource ...
after the zsh shell exits. Instead what you want to do isssh -t host zsh -d -f
to drop into an interactive shell on the remote host, or if you don't want an interactive shell, dossh host zsh -d -f -c \"source /path/to/file\; other command\; ... \"
. -
hjkatz almost 10 yearsNo 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 almost 10 yearsThis looks quite extravagant and I will give it a try as soon as possible. I'm hopeful this works!
-
jayhendren almost 10 yearsI 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 commandsource...
is NOT run inside the zsh shell. It's run in your login shell after the zsh shell exits. To test this out, runssh host "zsh; echo foo"
. You will see the output "foo" after you exit from the zsh shell. -
hjkatz almost 10 yearsYes, this is the problem. I don't want a login shell, I want interactive with the source command rum automatically. Unfortunately this seems to be difficult.
-
jayhendren almost 10 yearsI'm not sure you can do both, though you should be able to figure this out by reading the
INVOCATION
section of the zsh man pages. However, you can just setZDOTDIR
instead:ssh -t host ZDOTDIR=/path/to/rcfile zsh
-
hjkatz almost 10 yearsI was thinking about this, but I want to leave as little trace as possible. I could write a logout script that puts the
ZDOTDIR
back to what it was originally, but I want there to be an obvious solution. Why is it that zsh is on par and better than bash in all cases except for a simple task? It's just silly... -
Stéphane Chazelas almost 10 years@Le_Katz,
ZDOTDIR=x zsh
only setsZDOTDIR
for thatzsh
process (it addsZDOTDIR=x
to the environment that thatzsh
receives), there's nothing to put back after thatzsh
has exited (and.zlogout
is only evaluated for login shells) you might still want to unset ZDOTDIR from within your startup scripts if you don't want other zsh instanced called by thatzsh
to inherit it. -
hjkatz almost 10 years@StéphaneChazelas Woohoo! Thank you for clarifying! This works splendidly :D
-
Chris Perkins over 3 yearsThe emulate trick is cool and simple. Hope it does not have any side effects