.. _intro_zsh_command_process_substitution:

Command/Process Substitution
============================

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

.. code-block:: text
   :caption: Backtick and $(...) forms
   :name: command_process_substitution_forms

   % 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 :literal:`zsh`:

.. code-block:: text
   :caption: TTY and =cmd shortcuts
   :name: command_process_substitution_equals_cmd

   % 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 :literal:`=` prepended is replaced with its full pathname.  This can be very convenient.  If it's not convenient for you, you can turn it off:

.. code-block:: text
   :caption: Setting NO_EQUALS
   :name: command_process_substitution_no_equals

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

Another nice feature is process substitution:

.. code-block:: text
   :caption: Process sub with =(...)
   :name: command_process_substitution_equals_form

   % 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 :literal:`=(`...\ :literal:`)` is replaced with the name of a :emphasis:`file` containing its output.  (A command substitution, on the other hand, is replaced with the output itself.) :literal:`print -l` is like :literal:`echo`, excepts that it prints its arguments one per line, the way :literal:`fgrep` expects them:

.. code-block:: text
   :caption: print -l one per line
   :name: command_process_substitution_print_l

   % print -l foo bar
   foo
   bar

We could also have written:

.. code-block:: text
   :caption: =(...) with multiline echo
   :name: command_process_substitution_equals_echo

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

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

.. code-block:: text
   :caption: Edit process sub output
   :name: command_process_substitution_edit_output

   % 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:

.. code-block:: text
   :caption: Read compressed mail folder
   :name: command_process_substitution_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.

.. code-block:: text
   :caption: diff two process outputs
   :name: command_process_substitution_diff

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

If you read :literal:`zsh`'s man page, you may notice that :literal:`<(`...\ :literal:`)` is another form of process substitution which is similar to :literal:`=(`...\ :literal:`)`. There is an important difference between the two. In the :literal:`<(`...\ :literal:`)` 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 :literal:`=(`...\ :literal:`)` with :literal:`<(`...\ :literal:`)` in the examples above, all of them would have stopped working except for :literal:`fgrep -f <(`...\ :literal:`)`. You can not edit a pipe, or open it as a mail folder; :literal:`fgrep`, however, has no problem with reading a list of words from a pipe. You may wonder why :literal:`diff <(foo) bar` doesn't work, since :literal:`foo | diff - bar` works; this is because :literal:`diff` creates a temporary file if it notices that one of its arguments is :literal:`-`, and then copies its standard input to the temporary file.

:literal:`>(`...\ :literal:`)` is just like :literal:`<(`...\ :literal:`)` except that the command between the parentheses will get its input from the named pipe.

.. code-block:: text
   :caption: Output process sub >(...)
   :name: command_process_substitution_gt_form

   % dvips -o >(lpr) zsh.dvi
