Background
If you are a regular Linux user then you might already know of this or atleast seen these your shell scripts. For eg.
- ls -a 2>/dev/null
 
File descriptors
In simple words, when you open a file, the operating system creates an 
entry to represent that file and store the information about that opened
 file. So if there are 100 files opened in your OS then there will be 
100 entries in OS (somewhere in kernel). These entries are represented 
by integers like (...100, 101, 102....). This entry number is the file 
descriptor.
So it is just an integer number that uniquely represents an opened file 
in operating system.
If your process opens 10 files then your Process table will have 10 
entries for file descriptors.
File descriptors  0,1 and 2 are generally given to std input,  std output and std error streams for a process. So you cannot generally use them for anything else. 
At the file descriptor level, 
- stdin is defined to be file descriptor 0,
 - stdout is defined to be file descriptor 1, and
 - stderr is defined to be file descriptor 2.
 
NOTE : The FD (File descriptor) table in per process table. So 2 different process can have same FD on calling open(). This is abstraction on user side. On kernel side of things each opened file has a unique FD and two open files cannot have same FD. Please don't get confused.
Now that we know standard file descriptors created for each table lets see the redirection functions.
Redirection Basics
The > operator redirects the output usually to a file but it can be to a device.  You can also use >> to append.
- > file redirects stdout to file
 - 1> file redirects stdout to file
 - 2> file redirects stderr to file
 - &> file redirects stdout and stderr to file
 
NOTE : If you don't specify a number then the standard output stream is assumed but you can also redirect errors
NOTE :  As mentioned before you can use >> instead of > to append . 
Finally 
/dev/null is the null device it takes any input you want and throws it away. It can be used to suppress any output. 
Long story short - If you want any stream ignored redirect it to /dev/null
Now that we know the basics lets understand the functions
- 2>/dev/null : This means redirect stderr of the process to /dev/null which essentially mean discard it.
 - 2>&- : This will essentially close the output of stderr for a process.
 - 2>&1: This combines stdout and stderr into single stream.
 - |& : This is just an abbreviation for 2>&1 | (Added in bash4)
 - &>/dev/null : This is an abbreviation for > /dev/null 2>&1 which essentially means combine stdout and stderr and redirect it to /dev/null (discard it)
 - >/dev/null : This is again an abbreviation for 1 > /dev/null which means discard standard output. Incase you missed my point sometime back if you do not give a FD standard output stream is assumed.
 
Have written a script that attempts to recover accidentally deleted files that makes use of redirections -


Thank you! Can you please talk a bit more about 2>&-, especially the "-"?
ReplyDeleteThe general form of this one is D>&-, where "D" is a file descriptor number. This will close output for whichever file descriptor is referenced, i.e. "D".
DeleteFor eg. lets say I do -
aniket@aniket-Compaq-610:~/Downloads$ ls -a 1>&-
ls: write error: Bad file descriptor
Now lets understand why it outputted error. Since we did '1>&-' it basically terminated the stdout for the process. Now ls program tried to write the output to it and failed as it was already closed, hence the error.
It is basically used to close any stream for your command executed (based on file descriptor you give). Hope this helps.