[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Comments on bash 5.2's undocumented <(<file) and weird >(<file)
From: |
Emanuele Torre |
Subject: |
Re: Comments on bash 5.2's undocumented <(<file) and weird >(<file) |
Date: |
Fri, 5 Jul 2024 22:38:59 +0200 |
User-agent: |
Mutt/2.2.13 (00d56288) (2024-03-09) |
On Fri, Jul 05, 2024 at 04:10:55PM -0400, Dale R. Worley wrote:
> Emanuele Torre <torreemanuele6@gmail.com> writes:
> > Bash 5.2 apparently added <(< file) that expand to the path to a fifo
> > (openable only for read on BSD) to which the contents of file are
> > written to, without documenting it.
>
> I suspect that this is a consequence of
>
> The com‐
> mand substitution $(cat file) can be replaced by the equivalent but
> faster $(< file).
>
Yes, clearly that is influencing this new behaviour, but this is new:
<(<file) >(<file) did not have that special behaviour previously.
The <(<file) behaviour is neat, so it would be nice if at least that one
was documented.
> (Which oddly enough, I suggested for Bash some decades ago.) In the
> latter form, Bash doesn't set up a subprocess and then read the pipe
> from it but instead just reads the named file. Or rather, that was the
> initial implementation. I suspect that the code has been updated so
> that an "inner command" of "< file" now copies "file" to stdout (as if
> it was cat), and the various results you see are based on what the
> parent process does with that output.
More funny things have been discovered since.
It has been brought up when discussing this in the #bash IRC channel of
irc.libera.chat, that if you run eval '<file' in $(), the contents
of file are output to stdout, in every version of bash since it was
introduced.
So you can for example use this to concatenate two files in pure bash;
like $(cat <f; cat <g):
bash-5.2$ echo hi > f
bash-5.2$ echo ih > g
bash-5.2$ x=$(eval '<f'; eval '<g')
bash-5.2$ declare -p x
declare -- x=$'hi\nih'
And indeed to output a file to stdout in pure bash, in any version of
bash that has $(<):
bash-5.2$ printf hi\\nhello > file
bash-5.2$ { _=$(eval '< file' >&3) ;} 3<&1
hi
hellobash-5.2$
I have also noticed that if you source a file from $() and the last
logical line of that file contains only a simple command with only one
read-only stdin redirection, bash will also print out that file, again,
in all versions of bash with $(<):
bash-5.2$ printf hello > myfile
bash-5.2$ cat <<'EOF' > tosource
echo foo
< myfile
EOF
bash-5.2$ x=$(. ./tosource; echo hey)
bash-5.2$ declare -p x
declare -- x=$'foo\nhellohey'
>
> Dale
o/
emanuele6