Go to the first, previous, next, last section, table of contents.

Command/Process Substitution

Command substitution in zsh can take two forms. In the traditional form, a command enclosed in backquotes (`...`) is replaced on the command line with its output. This is the form used by the older shells. Newer shells (like zsh) also provide another form, $(...). This form is much easier to nest.

% ls -l `echo /vmunix`
-rwxr-xr-x  1 root      1209702 May 14 19:04 /vmunix
% ls -l $(echo /vmunix)
-rwxr-xr-x  1 root      1209702 May 14 19:04 /vmunix
% who | grep mad
subbarao ttyt7   May 23 15:02   (mad55sx15.Prince)
pfalstad ttyu1   May 23 16:25   (mad55sx14.Prince)
subbarao ttyu6   May 23 15:04   (mad55sx15.Prince)
pfalstad ttyv3   May 23 16:25   (mad55sx14.Prince)
% who | grep mad | awk '{print $2}'
ttyt7
ttyu1
ttyu6
ttyv3
% cd /dev; ls -l $(who |
> grep $(echo mad) |
> awk '{ print $2 }')
crwx-w----  1 subbarao  20,  71 May 23 18:35 ttyt7
crw--w----  1 pfalstad  20,  81 May 23 18:42 ttyu1
crwx-w----  1 subbarao  20,  86 May 23 18:38 ttyu6
crw--w----  1 pfalstad  20,  99 May 23 18:41 ttyv3

Many common uses of command substitution, however, are superseded by other mechanisms of zsh:

% ls -l `tty`
crw-rw-rw-  1 root      20,  28 May 23 18:35 /dev/ttyqc
% ls -l $TTY
crw-rw-rw-  1 root      20,  28 May 23 18:35 /dev/ttyqc
% ls -l `which rn`
-rwxr-xr-x  1 root       172032 Mar  6 18:40 /usr/princeton/bin/rn
% ls -l =rn
-rwxr-xr-x  1 root       172032 Mar  6 18:40 /usr/princeton/bin/rn

A command name with a = prepended is replaced with its full pathname. This can be very convenient. If it's not convenient for you, you can turn it off:

% ls
=foo    =bar
% ls =foo =bar
zsh: foo not found
% setopt noequals
% ls =foo =bar
=foo    =bar

Another nice feature is process substitution:

% who | fgrep -f =(print -l root lemke shgchan subbarao)
root     console May 19 10:41
lemke    ttyq0   May 22 10:05   (narnia:0.0)
lemke    ttyr7   May 22 10:05   (narnia:0.0)
lemke    ttyrd   May 22 10:05   (narnia:0.0)
shgchan  ttys1   May 23 16:52   (gaudi.Princeton.)
subbarao ttyt7   May 23 15:02   (mad55sx15.Prince)
subbarao ttyu6   May 23 15:04   (mad55sx15.Prince)
shgchan  ttyvb   May 23 16:51   (gaudi.Princeton.)

A command of the form =(...) is replaced with the name of a file containing its output. (A command substitution, on the other hand, is replaced with the output itself.) print -l is like echo, excepts that it prints its arguments one per line, the way fgrep expects them:

% print -l foo bar
foo
bar

We could also have written:

% who | fgrep -f =(echo 'root
> lemke
> shgchan
> subbarao')

Using process substitution, you can edit the output of a command:

% ed =(who | fgrep -f ~/.friends)
355
g/lemke/d
w /tmp/filbar
226
q
% cat /tmp/filbar
root     console May 19 10:41
shgchan  ttys1   May 23 16:52   (gaudi.Princeton.)
subbarao ttyt7   May 23 15:02   (mad55sx15.Prince)
subbarao ttyu6   May 23 15:04   (mad55sx15.Prince)
shgchan  ttyvb   May 23 16:51   (gaudi.Princeton.)

or easily read archived mail:

% mail -f =(zcat ~/mail/oldzshmail.Z)
"/tmp/zsha06024": 84 messages, 0 new, 43 unread
>  1  U  TO: pfalstad, zsh (10)
   2  U  nytim!tim@uunet.uu.net, Re: Zsh on Sparc1 /SunOS 4.0.3
   3  U  JAM%TPN@utrcgw.utc.com, zsh fix (15)
   4  U  djm@eng.umd.edu, way to find out if running zsh? (25)
   5  U  djm@eng.umd.edu, Re: way to find out if running zsh? (17)
   6   r djm@eng.umd.edu, Meta . (18)
   7  U  jack@cs.glasgow.ac.uk, Re: problem building zsh (147)
   8  U  nytim!tim@uunet.uu.net, Re: Zsh on Sparc1 /SunOS 4.0.3
   9     ursa!jmd, Another fix... (61)
  10  U  pplacewa@bbn.com, Re: v18i084: Zsh 2.00 - A small complaint (36)
  11  U  lubkin@cs.rochester.edu, POSIX job control (34)
  12  U  yale!bronson!tan@uunet.UU.NET
  13  U  brett@rpi.edu, zsh (36)
  14  S  subbarao, zsh sucks!!!! (286)
  15  U  snibru!d241s008!d241s013!ala@relay.EU.net, zsh (165)
  16  U  nytim!tim@uunet.UU.NET, Re: Zsh on Sparc1 /SunOS 4.0.3
  17  U  subbarao, zsh is a junk shell (43)
  18  U  amaranth@vela.acs.oakland.edu, zsh (33)
43u/84 1: x
% ls -l /tmp/zsha06024
/tmp/zsha06024 not found

Note that the shell creates a temporary file, and deletes it when the command is finished.

% diff =(ls) =(ls -F)
3c3
< fortune
---
> fortune*
10c10
< strfile
---
> strfile*

If you read zsh's man page, you may notice that <(...) is another form of process substitution which is similar to =(...). There is an important difference between the two. In the <(...) case, the shell creates a named pipe (FIFO) instead of a file. This is better, since it does not fill up the file system; but it does not work in all cases. In fact, if we had replaced =(...) with <(...) in the examples above, all of them would have stopped working except for fgrep -f <(...). You can not edit a pipe, or open it as a mail folder; fgrep, however, has no problem with reading a list of words from a pipe. You may wonder why diff <(foo) bar doesn't work, since foo | diff - bar works; this is because diff creates a temporary file if it notices that one of its arguments is -, and then copies its standard input to the temporary file.


Go to the first, previous, next, last section, table of contents.