$var
where var="foo bar"
not do what I expect?In most Bourne-shell derivatives, multiple-word variables such as
for foo in
$var
loop. By default, zsh does not have that behaviour: the
variable remains intact. (This is not a bug! See below.) An option
(shwordsplit) exists to provide compatibility.
For example, defining the function args to show the number of its arguments:
Unless you need strict sh/ksh compatibility, you should ask yourself whether you really want this behaviour, as it can produce unexpected effects for variables with entirely innocuous embedded spaces. This can cause horrendous quoting problems when invoking scripts from other shells. The natural way to produce word-splitting behaviour in zsh is via arrays. For example,
Note that this happens regardless of the value of the internal field
separator, $IFS
; in other words, with IFS=:; foo=a:b; args $foo
you get the answer 1.
Other ways of causing word splitting include a judicious use of `eval':
'
in this example,
must already be quoted), or, less standard but more reliable,
turning on shwordsplit for one variable only:
args
. (In older
versions of zsh, ${=foo}
toggled shwordsplit; now it forces it on.)
Note also the "$@"
method of word splitting is always available in zsh
functions and scripts (though strictly this does array splitting, not
word splitting).
Shwordsplit is set when zsh is invoked with the names `ksh' or `sh',
or (entirely equivalent) when emulate ksh
or emulate sh
is in
effect.
Normally, you would put a variable into the environment by using
export var
. The command setopt allexport
causes all
variables which are subsequently set (N.B. not all the ones which
already exist) to be put into the environment.
This may seem a useful shorthand, but in practice it can have unhelpful side effects:
for
loops. This is probably a waste.
In the first case, you presumably have setopt correctall
in an
initialisation file, so that zsh checks the spelling of each word in
the command line. You probably do not want this behaviour for
commands which do not operate on existing files.
The answer is to alias the offending command to itself with
nocorrect
stuck on the front, e.g.
To turn off globbing, the rationale is identical:
nocorrect
and noglob
, if you like, but the
nocorrect
must come first, since it is needed by the line editor,
while noglob
is only handled when the command is examined.
Note also that a shell function won't work: the no... directives must be expanded before the rest of the command line is parsed.
As stated in the manual, zsh needs to be told about the meta key by
using bindkey -me
or bindkey -mv
in your .zshrc or on the
command line. You probably also need to tell the terminal driver to
allow the `meta' bit of the character through; stty pass8
is the
usual incantation. Sample .zshrc entry:
You don't need the bindkey
to be able to define your own sequences
with the meta key, though you still need the stty
.
You should use the special function chpwd
, which is called when
the directory changes. The following checks that standard output is
a terminal, then puts the directory in the title bar if the terminal
is an xterm
or a sun-cmd
.
Change %~
if you want the message to be different. (The -P
option interprets such sequences just like in prompts, in this case
producing the current directory; you can of course use $PWD
here,
but that won't use the ~
notation which I find clearer.) Note that
when the xterm
starts up you will probably want to call chpwd
directly: just put chpwd
in .zshrc
after it is defined or autoloaded.
A traditional UNIX environment (character terminal and ASCII character sets) is not sufficient to be able to handle non-ASCII characters, and there are so many possible enhancements that in general this is hard. However, if you have something like an xterm using a standard character set like ISO-8859-1 (which is often the default for xterm), read on. You should also note question 3.4 on the subject of eight bit characters.
You are probably creating files with names including non-ASCII accented characters, and find they show up in the completion list as
The answer, under a modern POSIXy operating system, is to find a locale where these are treated as printable characters. Zsh has handling for locales built in and will recognise when you set a relevant variable. You need to look in /usr/lib/locale to find one which suits you; the subdirectories correspond to the locale names. The simplest possibility is likely to be en_US, so that the simplest answer to your problem is to set
when your terminal is capable of showing eight bit characters. If you only have a default domain (called C), you may need to have some additional files installed on your system.
The cursor keys send different codes depending on the terminal; zsh
only binds the most well known versions. If you see these problems,
try putting the following in your .zshrc
:
If you use vi mode, use vi-backward-char
and vi-forward-char
where appropriate.
Note, however, that up to version 3.0 binding arbitrary multiple key
sequences can cause problems, so check that this works with your set
up first. Also, from version 3.1.3, more sequences are supported by
default, namely those in the form <ESC>O
followed by A
,
B
, C
or D
, as well as the corresponding set beginning
<ESC>[
, so this may be redundant.
If you are using an OpenWindows cmdtool as your terminal, any escape sequences (such as those produced by cursor keys) will be swallowed up and never reach zsh. Either use shelltool or avoid commands with escape sequences. You can also disable scrolling from the cmdtool pane menu (which effectively turns it into a shelltool). If you still want scrolling, try using an xterm with the scrollbar activated.
If that's not the problem, and you are using stty to change some tty settings, make sure you haven't asked zsh to freeze the tty settings: type
On the other hand, if you aren't using stty and have problems you may
need the opposite: ttyctl -f
freezes the terminal to protect it
from hiccups introduced by other programmes (kermit has been known to
do this).
If that's not the problem, and you are having difficulties with
external commands (not part of zsh), and you think some terminal
setting is wrong (e.g. ^V
is getting interpreted as `literal next
character' when you don't want it to be), try
stty(1)
manual page).
At some point there may be an overhaul which allows the terminal modes used by the shell to be modified separately from those seen by external programmes. This is partially implemented already: from 2.5, the shell is less susceptible to mode changes inherited from programmes than it used to be.
(This information comes from Bart Schaefer and other zsh-workers.)
Emacs 19.29 or thereabouts stopped using a terminal type of "emacs" in shell buffers, and instead sets it to "dumb". Zsh only kicks in its special I'm-inside-emacs initialization when the terminal type is "emacs".
Probably the most reliable way of dealing with this is to look for
the environment variable $EMACS
, which is set to t
in
Emacs' shell mode. Putting
Another method is to put
chmod +x ~/bin/eshell
, and
tell emacs to use that as the shell by adding
The problem is that there are two possible ways of autoloading a function (see the AUTOLOADING FUNCTIONS section of the zsh manual page zshmisc for more detailed information):
function foo {
or foo () {
, and consequently no matching }
at the end.
This is the traditional zsh method. The advantage is that the
file is called exactly like a script, so can double as both.
To define a function xhead () { print -n "\033]2;$*\a"; }
,
the file would just contain print -n "\033]2;$*\a"
.
xhead
, the whole of the
usual definition should be in the file.
In old versions of zsh, before 3.0, only the first behaviour was allowed, so you had to make sure the file found for autoload just contained the function body. You could still define other functions in the file with the standard form for definitions, though they would be redefined each time you called the main function.
In version 3.0.x, the second behaviour is activated if the file defines the autoloaded function. Unfortunately, this is incompatible with the old zsh behaviour which allowed you to redefine the function when you called it.
From version 3.1, there is an option KSHAUTOLOAD to allow full ksh
compatiblity, i.e. the function must be in the second form
above. If that is not set, zsh tries to guess which form you are
using: if the file contains only a complete definition of the
function in the second form, and nothing else apart from comments
and whitespace, it will use the function defined in the file;
otherwise, it will assume the old behaviour. The option is set
if emulate ksh
is in effect, of course.
(A neat trick to autoload all functions in a given directory is to
include a line like autoload ~/fns/*(:t)
in .zshrc; the bit in
parentheses removes the directory part of the filenames, leaving
just the function names.)
The ksh syntax is now understood, i.e.
$(( ... ))
method will
always display in decimal.
You can place a literal newline in quotes, i.e.
unsetopt cshjunkiequotes
and setopt cshjunkiequotes
, or put it
in your .zshrc
before the option is set.
Arguably the prompt code should handle `print'-like escapes. Feel free to write this :-). Otherwise, you can use
bindkey ^a command-name
or stty intr ^-
do something funny?You probably have the extendedglob option set in which case ^
and #
are metacharacters. ^a
matches any file except one called a
, so the
line is interpreted as bindkey followed by a list of files. Quote the
^
with a backslash or put quotation marks around ^a
.
\C-s
and \C-q
any more?The control-s and control-q keys now do flow control by default,
unless you have turned this off with stty -ixon
or redefined the
keys which control it with stty start
or stty stop
. (This is
done by the system, not zsh; the shell simply respects these
settings.) In other words, \C-s
stops all output to the terminal,
while \C-q
resumes it.
There is an option NO_FLOW_CONTROL to stop zsh from allowing flow
control and hence restoring the use of the keys: put setopt
noflowcontrol
in .zshrc.
foo
within function foo
?The command command foo
does just that. You don't need this with
aliases, but you do with functions. Note that error messages like
foo
is a builtin rather than an external
command, use builtin foo
instead.
If you have a command like "echo !-2:$ !$
", the first history
substitution then sets a default to which later history substitutions
with single unqualified bangs refer, so that !$ becomes equivalent to
!-2:$
. The option CSH_JUNKIE_HISTORY makes all single bangs refer
to the last command.
Simple answer: you haven't asked it not to. Zsh (unlike [t]csh) gives
you the option of having background jobs killed or not: the nohup
option exists if you don't want them killed. Note that you can always
run programs with nohup
in front of the pipeline whether or not the
option is set, which will prevent that job from being killed on
logout. (nohup
is actually an external command.)
The disown
builtin is very useful in this respect: if zsh informs
you that you have background jobs when you try to logout, you can
disown
all the ones you don't want killed when you exit. This is
also a good way of making jobs you don't need the shell to know about
(such as commands which create new windows) invisible to the shell.
Tell zsh to start from entry 1: history 1
. Those entries at the
start which are no longer in memory will be silently omitted.
while {...} {...}
work?Zsh provides an alternative to the traditional sh-like forms with do
,
{...}
. The rules are quite complicated and
in most scripts it is probably safer --- and certainly more
compatible --- to stick with the sh-like rules. If you are
wondering, the following is a rough guide.
To make it work you must make sure the TEST itself is clearly delimited. For example, this works:
while
, any sort of command list is valid.
This includes the whole list let "i++ < 10"; { echo i $i; }
;
the parser simply doesn't know when to stop. Furthermore, it is
wrong to miss out the semicolon, as this makes the {...}
part
of the argument to let
. A newline behaves the same as a
semicolon, so you can't put the brace on the next line as in C.
So when using this syntax, the test following the while
must
be wrapped up: any of ((...))
, [[...]]
, {...}
or
(...)
will have this effect. (They have their usual syntactic
meanings too, of course; they are not interchangeable.) Note that
here too it is wrong to put in the semicolon, as then the case
becomes identical to the preceding one:
The same is true of the if
and until
constructs:
for
, which only needs a list of words, you can get
away with it:
repeat
,
case
or select
constructs; in fact, repeat
doesn't even
need the semicolon since it knows the repeat count is just one word.
This is independent of the behaviour of the SHORTLOOPS option (see manual), which you are in any case encouraged even more strongly not to use in programs as it can be very confusing.
In zsh, you need to set three variables to make sure your history is written out when the shell exits. For example,
$HISTSIZE
tells the shell how many lines to keep internally,
$HISTFILE
tells it where to write the history, and $SAVEHIST
,
the easiest one to forget, tells it how many to write out. The
simplest possibility is to set it to the same as $HISTSIZE
as
above. There are also various options affecting history; see the
manual.