In Bash, how to find the lowest-numbered unused file descriptor?

后端 未结 6 1817
梦毁少年i
梦毁少年i 2021-01-30 16:45

In a Bash-script, is it possible to open a file on \"the lowest-numbered file descriptor not yet in use\"?

I have looked around for how to do this, but it seems that Bas

6条回答
  •  野性不改
    2021-01-30 17:21

    In Basile Starynkevitch's answer to this question, on Nov 29 2011, he writes:

    If it is on Linux, you can always read the /proc/self/fd/ directory to find out the used file descriptors.

    Having done several experiments based on reading the fd directory, I have arrived at the following code, as the "closest match" to what I was looking for. What I was looking for was actually a bash one-liner, like

    my_file_descriptor=$(open_r /path/to/a/file)
    

    which would find the lowest, unused file descriptor AND open the file on it AND assign it to the variable. As seen in the code below, by introducing the function "lowest_unused_fd", I at least get a "two-liner" (FD=$(lowest_unused_fd) followed by eval "exec $FD<$FILENAME") for the task. I have NOT been able to write a function that works like (the imaginary) "open_r" above. If someone knows how to do that, please step forward! Instead, I had to split the task into two steps: one step to find the unused file descriptor and one step to open the file on it. Also note that, to be able to place the find step in a function ("lowest_unused_fd") and have its stdout assigned to FD, I had to use "/proc/$$/fd" instead of "/proc/self/fd" (as in Basile Starynkevitch's suggestion), since bash spawns a subshell for the execution of the function.

    #!/bin/bash
    
    lowest_unused_fd () {
        local FD=0
        while [ -e /proc/$$/fd/$FD ]; do
            FD=$((FD+1))
        done
        echo $FD
    }
    
    FILENAME="/path/to/file"
    
    #  Find the lowest, unused file descriptor
    #+ and assign it to FD.
    FD=$(lowest_unused_fd)
    
    # Open the file on file descriptor FD.
    if ! eval "exec $FD<$FILENAME"; then
        exit 1
    fi
    
    # Read all lines from FD.
    while read -u $FD a_line; do
        echo "Read \"$a_line\"."
    done
    
    # Close FD.
    eval "exec $FD<&-"
    

提交回复
热议问题