Search code examples
command-linezshio-redirection

Zsh redirection 2>>|


I came upon this which I am replicating in order to debug a zsh line editor widget, and I realized that I have no actual idea what 2>>| actually does. Presumably feed stderr into a file, but what's the deal with the |?


Solution

  • >>| is another example of how zsh chose to deviate from the POSIX standard:

    Note that the 2 in 2>> is incidental to the constructs discussed here; they work with either the default output stream - stdout, whose file descriptor is 1 - or any explicitly specified file descriptor, such as 2 for stderr in this case.

    >>| works somewhat analogously to the POSIX >| construct, but is only supported in zsh - the other major POSIX-compatible shells - bash, dash, ksh, and zsh do not support it.

    POSIX >| is meant to force replacement of an existing file even when the noclobber shell option is in effect, whose very purpose is to prevent such replacement ("clobbering") when just > is used.

    Note that noclobber is OFF by default in all of the above shells.

    POSIX does not mention an analogous >>| construct, and bash, dash, ksh indeed do not support it.
    The rationale is: since >> doesn't replace, but rather appends to an existing file, its operation is NOT affected by whether noclobber is in effect or not.
    In these shells, >> is always allowed - whether the output file already exists or not, whether noclobber is set or not (and, as stated, >>| is not supported at all).

    zsh begged to differ, and >> IS affected by whether noclobber is in effect or not: In an (arguably logical) reversal of the > / >| logic, with noclobber in effect, >> only works if the target file (already) exists.

    Accordingly, zsh supports >>| (or >>!) to force on-demand creation of the target file, even with noclobber in effect.


    There are several ways to set / unset the noclobber option in zsh:

    • POSIX-compliant ways:

      • zsh -C -c '...' - turn on via command-line option -C, when starting zsh
        • set -C - turn on with the set builtin
      • set -o noclobber - turn on by name

    As stated, noclobber is OFF by default, but you can explicitly turn it off by simply replacing -C with +C, or set -o with set +o.

    • zsh-specific ways:

      • setopt noclobber - equivalent of set -o noclobber
        • options[noclobber]=on - same as above
      • setopt clobber - equivalent of set +o noclobber
        • options[clobber]=on - same as above