Let’s start with some basics. The basics works as well on Unix, Linux and Windows. Later techniques only work on linux/unix
$ ls -l hosts -rw-r--r--. 1 root root 211 Oct 5 2015 hosts $ ls -l xxx ls: cannot access xxx: No such file or directory $ read x foo $
Outpout and error are displayed on screen and input is read from your keyboard
The output is kwown as file-descriptor-1 or stdout. Sometimes, depending on your OS, it may be exposed as /dev/fd/1 or /dev/stdout. But not all *nix have this.
The error is kwown as file-descriptor-2 or stderr.
The input is known as file-descriptor-0 or stdin.
Instead of keyboard and screen, it could be a file or any other devices, e.g. /dev/null or just a simple file.
$ ls -l hosts 1>file1 $ ls -l xxx 2>file2 $ read x 0<file3
0 and 1 are optional here.
If is also possible to redirect stdout and vice versa
$ ls -l hosts 1>&2 -rw-r--r--. 1 root root 211 Oct 5 2015 hosts $ ls -l xxx 2>&1 ls: cannot access xxx: No such file or directory
It is possible to close the file descriptor.
sleep 1 1>&- 2>&- 0<&-
Well, sleep has no output and no input and no error, so the effect is not impressive.
If you write to a closed file descriptor, you get an error. Ok, if you close both stdout and stderr, the error will be silent. But there will still be an error.
$ (echo foo) 1>&- bash: echo: write error: Bad file descriptor $ echo $? 1 $ (echo bar 1>&2) 2>&- $ echo $? 1
if you want to redirect stdin to stdout and stdout to stdin, you better use a new file descriptor
$ (ls -l hosts xxx 1>&2 2>&3) 3>&1 xxx not found -rw-rw-r-- 1 root system 2133 Jun 22 2017 hosts
An old trick is to use additional file descriptor to find a return code of command before the pipe.
$ ((((ls hosts; echo $? >&3) | tr '[a-z]' '[A-Z]' >&4) 3>&1) | (read rc; exit $rc)) 4>&1 HOSTS $ echo $? 0 $ ((((ls xxx; echo $? >&3) | tr '[a-z]' '[A-Z]' >&4) 3>&1) | (read rc; exit $rc)) 4>&1 ls: cannot access xxx: No such file or directory $ echo $? 2
As I know the trick for so long that I could not credit the author, only found some 21st century posts
If you want to redirect all your outputs to a logfile, you can use exec
#!/bin/ksh exec 1>>/tmp/mylog exec 2>>/tmp/mylog cd /etc ls -l hosts ls -l xxx exit
If you want to be able to still use your stdout / stderr, again, open new descriptors
#!/bin/ksh exec 3>&1 exec 4>&2 exec 1>>/tmp/mylog exec 2>>/tmp/mylog cd /etc ls -l hosts ls -l xxx echo INFO >&3 echo ERROR >&4 exec 3>&- exec 4>&- exit
Bash has also one shortcut
ls xxx host &>log
& redirect both 1 and 2 in one step. Doesn't work on ksh.