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
Apple Mac OS X is not Linux. I don't see any '/proc' file system on OS X.
I guess one answer is to use "zsh", but I want to have a script that works on both OS X (aka BSD) and Linux in "bash". So, here I am, in the year 2020, with the latest version of OS X, which at this moment is Catalina, and I realize that Apple seems to have abandoned maintenance of Bash long ago; apparently in favor of Zsh.
Here is my multi-OS solution to find the lowest unused file descriptor on Apple Mac OS X or Linux. I created an entire Perl script, and in-lined it into the Shell script. There must be a better way, but for now, this works for me.
lowest_unused_fd() {
# For "bash" version 4.1 and higher, and for "zsh", this entire function
# is replaced by the more modern operator "{fd}", used like this:
# exec {FD}>myFile.txt; echo "hello" >&$FD;
if [ $(uname) = 'Darwin' ] ; then
lsof -p $$ -a -d 0-32 | perl -an \
-e 'BEGIN { our @currentlyUsedFds; };' \
-e '(my $digits = $F[3]) =~ s/\D//g;' \
-e 'next if $digits eq "";' \
-e '$currentlyUsedFds[$digits] = $digits;' \
-e 'END { my $ix;
for( $ix=3; $ix <= $#currentlyUsedFds; $ix++) {
my $slotContents = $currentlyUsedFds[$ix];
if( !defined($slotContents) ) {
last;
}
}
print $ix;
}' ;
else
local FD=3
while [ -e /proc/$$/fd/$FD ]; do
FD=$((FD+1))
done
echo $FD
fi;
}
The -an
options to Perl tells it to (-n
) run an implied while()
loop that reads the file line by line and (-a)
auto-split it into an array of words which, by convention, is named @F
. The BEGIN
says what to do before that while()
loop, and the END
says what to do after. The while()
loop picks out field [3]
of each line, reduces it to just its leading digits, which is a port number, and saves that in an array of port numbers that are currently in use, and therefore are unavailable. The END
block then finds the lowest integer whose slot is not occupied.
Update: After doing all that, I actually am not using this in my own code. I realized that the answer from KingPong and Bruno Bronsky is far more elegant. However, I will leave this answer in place; it might be interesting to somebody.