Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: file descriptors

Tags:

bash

I am a Bash beginner but I am trying to learn this tool to have a job in computers one of these days.

I am trying to teach myself about file descriptors now. Let me share some of my experiments:


#!/bin/bash

# Some dummy multi-line content
read -d '' colours <<- 'EOF'
        red
        green
        blue
EOF

# File descriptor 3 produces colours
exec 3< <(echo "$colours")

# File descriptor 4 filters colours
exec 4> >(grep --color=never green)

# File descriptor 5 is an unlimited supply of violet
exec 5< <(yes violet)

echo Reading colours from file descriptor 3...
cat <&3
echo ... done.

echo Reading colours from file descriptor 3 again...
cat <&3
echo ... done.

echo Filtering colours through file descriptor 4...
echo "$colours" >&4
echo ... done. # Race condition?

echo Dipping into some violet...
head <&5
echo ... done.

echo Dipping into some more violet...
head <&5
echo ... done.

Some questions spring to mind as I see the output coming from the above:

  1. fd3 seems to get "depleted" after "consumption", is it also automatically closed after first use?
  2. how is fd3 different from a named pipe? (something I have looked at already)
  3. when exactly does the command yes start executing? upon fd declaration? later?
  4. does yes stop (CTRL-Z or other) and restart when more violet is needed?
  5. how can I get the PID of yes?
  6. can I get a list of "active" fds?
  7. very interesting race condition on filtering through fd4, can it be avoided?
  8. will yes only stop when I exec 5>&-?
  9. does it matter whether I close with >&- or <&-?

I'll stop here, for now.

Thanks!

PS: partial (numbered) answers are fine.. I'll put together the different bits and pieces myself.. (although a comprehensive answer from a single person would be impressive!)

like image 253
Robottinosino Avatar asked Mar 25 '13 01:03

Robottinosino


People also ask

How do I view file descriptors in Linux?

Use the ulimit -n command to view the number of file descriptors configured for your Linux system.

What are the 3 standard file descriptors?

Stdin, stdout, and stderr On a Unix-like operating system, the first three file descriptors, by default, are STDIN (standard input), STDOUT (standard output), and STDERR (standard error). The default data stream for input, for example in a command pipeline.

How do I use file descriptors in Linux?

On Linux, the set of file descriptors open in a process can be accessed under the path /proc/PID/fd/ , where PID is the process identifier. File descriptor /proc/PID/fd/0 is stdin , /proc/PID/fd/1 is stdout , and /proc/PID/fd/2 is stderr .

How do I redirect a file in bash?

For utilizing the redirection of bash, execute any script, then define the > or >> operator followed by the file path to which the output should be redirected. “>>” operator is used for utilizing the command's output to a file, including the output to the file's current contents.


1 Answers

fd3 seems to get "depleted" after "consumption", is it also automatically closed after first use?

No, it is not closed. This is due to the way exec works. In the mode in which you have used exec (without arguments), its function is to arrange the shell's own file descriptors as requested by the I/O redirections specified to itself, and then leave them that way until the script terminated or they are changed again later.

Later, cat receives a copy of this file descriptor 3 on its standard input (file descriptor 0). cat's standard input is implicitly closed when cat exits (or perhaps, though unlikely, cat closes it before it exists, but that doesn't matter). The original copy of this file, which is the shell's file descriptor 3, remains. Although the actual file has reached EOF and nothing further will be read from it.

how is fd3 different from a named pipe? (something I have looked at already)

The shell's <(some command) syntax (which is not standard bourne shell syntax and I believe is only available in zsh and bash, by the way) might actually be implemented using named pipes. It probably isn't under Linux because there's a better way (using /dev/fd), but it probably is on other operating systems.

So in that sense, this syntax may or may not be a helper for setting up named pipes.

when exactly does the command yes start executing? upon fd declaration? later?

As soon as the <(yes violet) construct is evaluated (which happens when the exec 5< <(yes violet) is evaluated).

does yes stop (CTRL-Z or other) and restart when more violet is needed?

No, it does not stop. However, it will block soon enough when it starts producing more output than anything reading the other end of the pipe is consuming. In other words, the pipe buffer will become full.

how can I get the PID of yes?

Good question! $! appears to contain it immediately after yes is executed. However there seems to be an intermediate subshell and you actually get the pid of that subshell. Try <(exec yes violet) to avoid the intermediate process.

can I get a list of "active" fds?

Not from the shell. But if you're using an operating system like Linux that has /proc, you can just consult /proc/self/fd.

very interesting race condition on filtering through fd4, can it be avoided?

To avoid it, you presumably want to wait for the grep process to complete before proceeding through the script. If you obtain the process ID of that process (as above), I think you should be able to wait for it.

will yes only stop when I exec 5>&-?

Yes. What will happen then is that yes will continue to try to produce output forever but when the other end of the file descriptor is closed it will either get a write error (EPIPE), or a signal (SIGPIPE) which is fatal by default.

does it matter whether I close with >&- or <&-?

No. Both syntaxes are available for consistency's sake.

like image 59
Celada Avatar answered Oct 02 '22 18:10

Celada