107

I saw this line in a script:

DEVICE=`dialog --inputbox "Festplatten-Laufzeit auslesen. Gebe Sie das 
gewünschte Device an: " 0 70 "" 3>&1 1>&2 2>&3`

What is

3>&1 1>&2 2>&3

doing? I know that 1 = stdout and 2 = stderr, but what are the 3 and the & for?

αғsнιη
  • 41,407
jsterr
  • 1,341

4 Answers4

119

The numbers are file descriptors and only the first three (starting with zero) have a standardized meaning:

0 - stdin
1 - stdout
2 - stderr

So each of these numbers in your command refer to a file descriptor. You can either redirect a file descriptor to a file with > or redirect it to another file descriptor with >&

The 3>&1 in your command line will create a new file descriptor and redirect it to 1 which is STDOUT. Now 1>&2 will redirect the file descriptor 1 to STDERR and 2>&3 will redirect file descriptor 2 to 3 which is STDOUT.

So basically you switched STDOUT and STDERR, these are the steps:

  1. Create a new fd 3 and point it to the fd 1
  2. Redirect file descriptor 1 to file descriptor 2. If we wouldn't have saved the file descriptor in 3 we would lose the target.
  3. Redirect file descriptor 2 to file descriptor 3. Now file descriptors one and two are switched.

Now if the program prints something to the file descriptor 1, it will be printed to the file descriptor 2 and vice versa.

Ulrich Dangel
  • 25,369
  • You have said "The 3>&1 in your command line will create a new file descriptor and redirect it to 1 which is STDOUT" . But doesn't 1 means STDIN ? – sofs1 Aug 10 '19 at 09:16
  • 1
    @sofs1 STDIN is 0; STDOUT is 1; STDERR is 2 I believe. – Lou Dec 14 '20 at 10:02
  • 2
    My question is - how does a shell script know what to pass to "3"? Say you ran a echo "hello" | 3>&1 - would it pipe "hello" to the 3 file descriptor, and then to STDOUT? – Lou Dec 14 '20 at 10:04
  • @Lou Normally there would be a command after the | symbol. There is none, and it seems like Bash pipes "hello" to nowhere in that case. – user234461 Aug 09 '21 at 08:57
  • @Lou But if you meant what does echo "hello" 3>&1 do, or similar, then it pipes "hello" to STDOUT, and also directs 3 to stdout. But 3 never receive a stream so the 3>&1 has no effect. It's just like the more common 2>&1, which combines STDERR with STDOUT into a single stream on STDOUT. – user234461 Aug 09 '21 at 09:01
36

It's swapping stdout and stderr.

>name means redirect output to file name.

>&number means redirect output to file descriptor number.

So the & is needed to tell the shell you mean a file descriptor, not a file name.

A file descriptor is a number that refers to an already open file. The standard ones are 0 for standard input, 1 for standard output or 2 for standard error. You can also use any other number, which will create a new file descriptor, just like when you create a new variable with var=value.

By default, both file descriptor 1 and 2 go to /dev/tty, so if you run somecommand 3>&1 1>&2 2>&3 in a new shell, it doesn't change anything (except now you have a file descriptor number 3).

But if somewhere earlier in the script it does a redirection using exec (e.g. exec 2>error.log), or the script is run with a command line including redirection (e.g. ./thescript 2>error.log), then swapping stdout and stderr will do something.

In your specific case, the command that's having its stdout and stderr swapped is dialog. Looking at its man page, I see

Some widgets, e.g., checklist, will write text to dialog's output.
Normally that is the standard error

so perhaps the person who wrote the script wants dialog's output to go to stdout instead of stderr for some reason.

See also Order of redirections

Mikel
  • 57,299
  • 15
  • 134
  • 153
  • 1
    Upvoted thanks to the "Order of redirections" link. My previous understanding (that I've had for 20+ years) was that 2>&1 means "redirect the content that goes to STDERR to STDOUT instead". But what it actually means is "file descriptor 2 now points to the same file as file descriptor 1". Based on my previous understanding, OP's question was confusing to me too, and the top voted answer was not helpful. Only the "Order of Redirection" link could help me understand what's happening, as it gave me the proper understanding of what 2>&1 really means. Never too late to learn! ;) Thank you! – msb Apr 28 '23 at 18:24
  • A better, more illuminating and comprehensive answer than the one accepted, IMHO. Accepted answer is still good; but this one is better. – DryLabRebel Jun 19 '23 at 05:10
6

The script writer defined fd 3 such as:

exec 3<> File.txt

Open "File.txt" and assign fd 3 to it. Maximum file descriptors: 255

read -n 4 <&3

Read only 4 characters.

echo -n . >&3

Write a decimal point there.

exec 3>&-

Close fd 3.

cat File.txt

==> 1234.67890

  • 2
    https://www.tldp.org/LDP/abs/html/io-redirection.html – Jonathan Jackson Feb 01 '19 at 22:42
  • The file descriptor limit is set by the "open files" option. The command ulimit -uS will show the soft limit of that option. (1204 in my case) while the ulimit -uH will show you the hard limit. – Angel115 Jan 23 '21 at 10:42
0

I understood the purpose of the file descriptor and the "3> & 1 1> & 2 2> & 3" command by example below

#!/bin/bash
#it's normal case fd environment

echo test 1> afile.txt echo "Test no 1" cat afile.txt echo "Test no 1"

echo test 2> afile.txt echo "Test no 2" cat afile.txt echo "Test no 2"

echo test 1> afile.txt echo "Test no 3" cat afile.txt echo "Test no 3" echo test 2> afile.txt

echo "Test no 4" cat afile.txt echo "Test no 4" echo > afile.txt

echo "------------------------------------------------------------------------"

#it's relocate filedescriptor and cause not problem, and cause error(std error)

var= var=$(echo test 3>&1 1>&2 2>&3)

echo "Test no 5" #cat afile.txt echo $var echo "Test no 5"

var= var=$(echo test 3>&1 1>&2 2>&3)

echo "Test no 6" #cat afile.txt echo $var echo "Test no 6"

var= var=$(echo test 3>&1 1>&2 2>&3)

echo "Test no 7" #cat afile.txt echo $var echo "Test no 7"

var= var=$(echo test 3>&1 1>&2 2>&3)

echo "Test no 8" #cat afile.txt echo $var echo "Test no 8"

When you run this example, you will see the file descriptors are rearranged and the output changes.

Pablo A
  • 2,712