[Please edit your question; the title makes no sense, as that could be done with the simple > file
redirection from the first row]
The missing rows could be done in bash with the 2> >(...)
and > >(...)
redirection + process substitution combinations.
E.g. for the most useful case (see full table at the end):
# both stderr+stdout to the tty, only stderr to the file
$ ls -d /etc /etx 2> >(tee file)
/etc
ls: cannot access '/etx': No such file or directory
$ cat file
ls: cannot access '/etx': No such file or directory
Notice though that > >(...)
tends to be tricky and buggy. Even when working fine, the stdout and stderr may come mixed up, or after the prompt:
bash$ sh -c 'sleep .1; ls -d /etc /etx' 2> >(tee errors)
ls: cannot access '/etx'/etc
: No such file or directory
bash$ ls -d /etc /etx 2> >(sleep .1; tee errors)
/etc
bash$ ls: cannot access '/etx': No such file or directory
Portably, it could be done by swapping the stdout and stderr with 3>&2 2>&1 >&3 3>&-
:
$ ls -d /etc /etx 3>&1 >&2 2>&3 3>&- | cat | tee file
ls: cannot access '/etx': No such file or directory
/etc
$ cat file
ls: cannot access '/etx': No such file or directory
Note: the "useless" cat is needed in order to dodge around tee's input buffering; stdbuf -i0 tee file
should work too. Having the different outputs mixed up will always be a problem when you have multiple processes writing to the same place, which afaik cannot be fixed without intercepting the actual fprintf
and similar calls within the application itself.
Tables
The appending forms were omitted; you can easily get them by replacing tee file
with tee -a file
and >file
with >>file
. The ... tee /dev/fd/3 ... 3 >&1 or 3>&2 ...
commands could be simplified to tee /dev/tty
if they're only intended to be run from an interactive terminal.
bash
TERMINAL FILE
OUT ERR OUT ERR
yes yes yes yes cmd |& tee file
yes yes yes no cmd | tee file
yes yes no yes cmd 2> >(tee file)
yes yes no no cmd
yes no yes yes (cmd | tee /dev/fd/3) 3>&1 &>file
yes no yes no cmd 2>/dev/null | tee file
yes no no yes cmd 2>file
yes no no no cmd 2>/dev/null
no yes yes yes (cmd 2> >(tee /dev/fd/3)) 3>&2 &>file
no yes yes no cmd >file
no yes no yes cmd 2> >(tee file) >/dev/null
no yes no no cmd >/dev/null
no no yes yes cmd &>file
no no yes no cmd >file 2>/dev/null
no no no yes cmd >/dev/null 2>file
no no no no cmd &>/dev/null
Standard /bin/sh
TERMINAL FILE
OUT ERR OUT ERR
yes yes yes yes cmd 2>&1 | tee file
yes yes yes no cmd | tee file
yes yes no yes cmd 3>&2 2>&1 >&3 3>&- | tee file
yes yes no no cmd
yes no yes yes (cmd | tee /dev/fd/3) 3>&1 >file 2>&1
yes no yes no cmd 2>/dev/null | tee file
yes no no yes cmd 2>file
yes no no no cmd 2>/dev/null
no yes yes yes (cmd 4>&2 2>&1 >&4 4>&- | tee /dev/fd/3) 3>&1 >file 2>&1
no yes yes no cmd >file
no yes no yes cmd 2>&1 >/dev/null | tee file
no yes no no cmd >/dev/null
no no yes yes cmd >file 2>&1
no no yes no cmd >file 2>/dev/null
no no no yes cmd >/dev/null 2>file
no no no no cmd >/dev/null 2>&1
tee
command doesn't have such an option - but you can simply redirect stdout to /dev/null (> /dev/null
) if you don't want it to be displayed in the terminal – steeldriver Oct 28 '20 at 00:41tee
at all? Doesn't standard>
redirection do what you want? – Stephen Harris Oct 28 '20 at 01:00