LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   file descriptor - exec vs inline (https://www.linuxquestions.org/questions/linux-newbie-8/file-descriptor-exec-vs-inline-4175731861/)

jt1122 12-16-2023 10:27 AM

file descriptor - exec vs inline
 
Hi,

What's the difference between using file descriptors (fd) with & without exec?

Example:
This reads a single line on fd 5 from file f:
Code:

read -u5 i 5<f
is the fd "auto" closed after the command finishes?.

With exec (fd opened & closed manually):
Code:

exec 5<f ; read -u5 i ; exec  5<&-
So the difference is that with exec the fd is permanent until it's manually closed?.

Thanks

pan64 12-16-2023 10:33 AM

Code:

read -u5 i 5<f
redirection ( < ) will be valid only during the execution of the command (read).
Code:

exec 5<f
this is a permanent redirection, will be valid until it is closed or the shell exited.
But you know it already.

jt1122 12-16-2023 10:38 AM

Thanks :thumbsup:

So in the example I've given fd 5 will auto-closed after the read command finishes?.

sundialsvcs 12-16-2023 02:41 PM

Quote:

Originally Posted by pan64 (Post 6470781)
this is a permanent redirection, will be valid until it is closed or the shell exited.
But you know it already.

Worth pointing out, however, that this sort of thing is a bad idea because most programmers will not know to expect it when they are looking for a bug ... this qualifies as "a surprise."

MadeInGermany 12-16-2023 06:45 PM

Code:

read -u5 i 5<f
The shell opens and closes the file just for this one command.
No need for the extra descriptor here.
Code:

read i <f
The shell opens and closes the file via stdin, then the original stdin continues.

The exec lets the shell permanently open the file. Until it's closed with another exec.
Code:

exec 5<f
read -u5 line1
read -u5 line2
exec 5<&-

The extra descriptor makes sense, because I could access the stdin in addition.
But I prefer a code block in favor of an exec/exec.
Code:

{
read -u5 line1
read -u5 line2
} 5<f

The shell opens/closes the file at the beginning/end of the block.
If the block is very long, I usually put a comment at the beginning:
Code:

# &5 is from file f
BTW the -u is never really needed; the standard shell has
Code:

{
read line1 <&5
read line2 <&5
} 5<f


pan64 12-17-2023 02:48 AM

Quote:

Originally Posted by MadeInGermany (Post 6470836)
Code:

read -u5 i 5<f
The shell opens and closes the file just for this one command.
No need for the extra descriptor here.
Code:

read i <f
The shell opens and closes the file via stdin, then the original stdin continues.

Yes, the latter is better, the original way may fail if fd=5 is already in use.

Quote:

Originally Posted by MadeInGermany (Post 6470836)
The exec lets the shell permanently open the file. Until it's closed with another exec.
Code:

exec 5<f
read -u5 line1
read -u5 line2
exec 5<&-

The extra descriptor makes sense, because I could access the stdin in addition.

To avoid conflict with existing (already used file descriptors) you can try to use 99 instead of 5, but there is a way to dynamically and automatically find the next free one:

Code:

exec {FD}<f
read -u$FD line1
read -u$FD line2
exec $FD<&-


https://tldp.org/LDP/abs/html/io-redirection.html

syg00 12-17-2023 03:28 AM

My needs in these things are always modest, but I do enjoy the discussions. Thanks to all.

MadeInGermany 12-17-2023 04:35 AM

Only the exec overwrites a previous file descriptor!
A redirected command sets a file descriptor in a new context:
Code:

exec 5< /etc/nsswitch.conf
read -u 5 passwd1 5< /etc/passwd
read -u 5 nsswitch1
exec 5<&-

echo "$nsswitch1"
echo "$passwd1"

Behind the scene the shell forks; in the forked shell it sets the descriptor then execs the command.

Regarding the redirected code block, it opens a new descriptor context but not a new shell scope (no fork).
Example with nested code blocks:
Code:

exec 5< /etc/nsswitch.conf
{
  {
    read -u 5 passwd1
  } 5< /etc/passwd
  read -u 5 group1
} 5< /etc/group
read -u 5 nsswitch1
exec 5<&-
 
echo "$nsswitch1"
echo "$passwd1"
echo "$group1"

The old Bourne shell forked a sub shell for a redirected code block; shell variables and settings in the sub shell were lost when back in the main shell.
A modern shell avoids a sub shell, unless you enforce it by using ( ) instead of { }
But a pipe from/to a code block still enforces a sub shell.
Code:

echo hello | while read i; do echo "Sub shell: i=$i"; done
echo "Back in the main shell: i=$i"

The while-do-done block is a code block.

BTW even for-do-done if-then-fi case-esac are code blocks. For ex you can do
Code:

if [ "$1" = "head" ]
then
  head
else
  tail
fi < /etc/group



All times are GMT -5. The time now is 01:23 AM.