Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the purpose of these redirections and file descriptors?

Tags:

bash

shell

I saw the following shell script. I think I get the basic idea of what it is doing, but I still do not understand what is the purpose of using so many redirections and file descriptors? For example, exec 3>&1, do something 2>&1 1>&3 and exec 3>&-.

#-Open file descriptor (fd)
exec 3>&1

#-Create a form and then store data to $VALUES variable
VALUES=$(dialog \
    --keep-tite \
    --ok-label "Submit" \
    --backtitle "Linux User Managment" \
    --title "Useradd" \
    --form "Create a new user" \
    15 50 0 \
    "Username:" 1 1 "$user"     1 10 10 0 \
    "Shell:"    2 1 "$shell"    2 10 15 0 \
    "Group:"    3 1 "$groups"   3 10 8 0 \
    "HOME:"     4 1 "$home"     4 10 40 0 \
2>&1 1>&3)

# close fd
exec 3>&-

# display values just entered
echo "$VALUES"

Could you please tell me why they are necessary? Is it because the dialog utility that is being used? I ask because I've never seen people doing this in simple commands, like ls etc.

exec 3>&1
ls 2>&1 1>&3
exec 3>&-
like image 332
Daniel Avatar asked Feb 13 '23 19:02

Daniel


2 Answers

Normally dialog displays its dialog box to the user through stdout, which is file descriptor 1, reads the user's keystrokes from stdin, which is file descriptor 0, and outputs the values filled in by the user to stderr, which is file descriptor 2.

The reason for bringing in an extra file descriptor is to read the values through $(command…) substitution (same as backquotes). Command substitution takes whatever the inner command (in this case, dialog…) sent to its stdout and fills it into the outer command (in this case, VALUES=…).

The 2>&1 redirection makes dialog send the field values to its stdout, where they will be captured into VALUES. So, dialog needs a different file descriptor to display the dialog box to the user. The exec 3>&1 duplicates the original stdout file descriptor. That is, after that command, file descriptor 3 and file descriptor 1 refer to the same file—the original stdout. The 1>&3 redirection makes dialog display its dialog to that original stdout.

To put that another way, the reason for bringing in file descriptor 3 is to temporarily "save" stdout.

like image 126
Ben Kovitz Avatar answered Feb 19 '23 00:02

Ben Kovitz


The breakdown is simple:

exec 3>&1

Anything written to file descriptor 3 will go the same place as file descriptor 1, standard output.

VALUES=$(command ...arguments... 2>&1 1>&3)

Here, anything written to file descriptor 2, standard error, will go the same place as file descriptor 1, standard output. However, the definition of standard output is then changed so that anything written to standard output goes to the same place as file descriptor 3. This is inside a command substitution $(...) operation, so the standard output is normally captured in a file. It means that the variable VALUES gets to hold whatever the command writes to standard error, while the original standard output gets whatever the command writes to standard output.

Finally:

exec 3>&-

closes file descriptor 3; attempts to write to it will fail from here on.

Your simulation of the command should be:

exec 3>&1
variable=$(ls 2>&1 1>&3)
exec 3>&-

This would capture any errors from ls in $variable, while allowing you to see whatever ls wrote on standard output. You don't see this sort of thing done normally because the requirements are a bit unusual.

like image 43
Jonathan Leffler Avatar answered Feb 19 '23 01:02

Jonathan Leffler