[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: redirection / process substitution fails to read a file descriptor
From: |
Mike Peters |
Subject: |
Re: redirection / process substitution fails to read a file descriptor |
Date: |
Sun, 17 Nov 2024 12:16:40 -0600 |
User-agent: |
Mozilla Thunderbird |
On 2024-11-16 22:56, Lawrence Velázquez wrote:
On Sat, Nov 16, 2024, at 9:35 PM, Greg Wooledge wrote:
On Sat, Nov 16, 2024 at 16:35:05 -0600, Mike Peters wrote:
Description:
Process substitution does not generate properly when pulling from another file
descriptor, although it works when pulling from a file directly. In the below sample shell
session, it is expected that `<(<test.txt)` would be functionally equivalent to
`<(<&3)`.
Repeat-By:
> echo foobar > test.txt
> echo `< <(<test.txt)`
foobar
Be aware that <(<file) is undocumented and was removed [1] after
Emanuele brought it up [2]; it will not work in future releases.
I don't know what documentation it was missing from, but this usage is consistent and logically valid with
the manual... Process substitution 'takes the form of <(list) or >(list)'. The grammar defines 'list'
to be 'a sequence of one or more pipes', a 'pipeline' to be 'a sequence of one or more commands'. Command
substitution takes the form $(command) or `command`, and since `<file` is valid as specified by the cat
shortcut, <file must be a valid simple command. SIMPLE COMMAND EXPANSION explicit allows redirections*:
"If no command name results, redirections are performed, but do not affect the current shell
environment." Thus the manual's grammar technically does document the validity of <(<file).
I hope it's removal is documented in the manual.
* (Although I have yet to determine any purpose or significance of these redirections in the
manual, other than simply not causing an error, as it "do[es] not affect the current shell
environment", and there is "no command name", so what is there remaining to affect?)
However, the "issue" does affect command substitutions:
$ echo foobar >test.txt
$ echo "$(<test.txt)"
foobar
$ exec 3<test.txt
$ echo "$(<&3)"
$
[1]
https://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel&id=d3e86e66ce857a8dc02e3116fd98b6e5b34d6364
[2] https://lists.gnu.org/archive/html/bug-bash/2024-07/msg00045.html
I'm guessing that the parser sees the <& and decides *not* to treat
this as a shortcut of cat with &3 as a filename. Therefore, the only
thing the parser can do is treat this as an empty command with a <&3
redirection attached to it.
As I understand the code [3][4], <file ("r_input_direction") is a
candidate for the "cat" optimization, <&n ("r_duplicating_input")
isn't, and the decision is made after parsing, so there's no way
&n could be interpreted as a filename.
Note that the actual documentation for this feature doesn't say or
imply that <&n should work:
The command substitution $(cat file) can be replaced by the
equivalent but faster $(< file).
Agreed. I had a mistaken understanding. I took too much liberty in
interpretation.
This reading doesn't make much sense:
The command substitution $(cat &n) can be replaced by the
equivalent but faster $(< &n).
There might be an argument for it if the documentation read:
The command substitution $(cat <file) can be replaced by
the equivalent but faster $(<file).
But it doesn't.
I disagree. The REDIRECTION section of the manual uses the word 'word' when it might
refer to either a file descriptor or a file, so I think "there might be an
argument" if the declaration involved incorporating 'word' in place of 'file'.
[3]
https://git.savannah.gnu.org/cgit/bash.git/tree/builtins/evalstring.c?h=devel&id=fa68e6da80970c302948674369d278164a33ed39#n198
[4]
https://git.savannah.gnu.org/cgit/bash.git/tree/make_cmd.c?h=devel&id=fa68e6da80970c302948674369d278164a33ed39#n663
Mike Peters