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 This is one of the most convoluted things I've seen in a long time. You've got a command substitution with < as its command, which is equivalent to $(cat ...) as a bash extension. The argument of </cat is a process substitution with a *second* instance of < being used as a command. So, going from the innermost layer outward, you have a process substitution which reads a file's contents and dumps it to the procsub's FD (the way cat would), and this FD is being treated as a filename by a command substitution's </cat which in turn dumps the data to the commsub's internal pipe. The commsub read the content from the procsub FD and is replaced by that content, which happens to be the string "foobar". This is passed as an argument to echo. > > exec 3<test.txt > > cat <&3 > foobar OK. This part is straightforward. Note that you used a command, cat, to write output. You didn't simply type <&3 without a command. > > exec 3<test.txt > > echo `< <(<&3)` > > > Here, you've got a process substitution with <&3 inside it. I can only guess what this is going to do. It doesn't follow the standard form of < filename which would be treated like cat filename, even though it begins with a < character. 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. So, your process runs an empty command with a stdin redirection, which produces no output. The procsub therefore receives no data. So the filename that the procsub is replaced by may as well be a symlink to /dev/null. Then, you have the command substitution with < followed by that filename, which contains no data. The commsub produces no output, so it's replaced by nothing. (The commsub is not quoted, so it simply vanishes, leaving echo with no arguments.) echo is executed with no arguments, so it writes a newline to stdout. If you expected the inner process substitution to generate output, then there needs to be a command of some kind inside it, and that command should write to stdout. The obvious pick would be cat. In the *first* segment of code, your inner process substitution had the < command inside it, which acts like cat, because of a bash extension. You're missing that in the final code segment.