I was reading the bash man docs for here strings/documents:
Here Strings
A variant of here documents, the format is:
[n]<<<word
The word undergoes tilde expansion, parameter and variable expansion, command substitution, arithmetic expan‐
sion, and quote removal. Pathname expansion and word splitting are not performed. The result is supplied as a
single string, with a newline appended, to the command on its standard input (or file descriptor n if n is
specified).
Since it says the word
is appended to file descriptor if n if n is specified
, I was wondering if we can write to STDOUT
just using it.
But when I tried it, it did not work:
1<<<test
It does not raise any error but seems to do nothing. When exec, I got:
exec 1<<<test
-bash: echo: write error: Bad file descriptor
I know that I can use read
, cat
, dd
, and other commands to do it... but
What I'm missing here? why it does not work as I understood it should?
CodePudding user response:
You're misreading the description. It doesn't say word is appended to anything, it says it is "...supplied as a single string, with a newline appended, to the command...". So it's a newline being appended to word, not word being appended to anything.
word plus a newline is "supplied" to the command. That means it is made available (in the form of a file, or pipe, or something like that) for the command to read as input, either on FD 0 (standard input aka stdin) by default, or some other FD if a number is specified. So someCommand 3<<<"test"
is essentially equivalent to:
echo "test" >tempfile
someCommand 3<tempfile
If the command doesn't read from that FD (3 in my example here), then the redirection doesn't do anything. The input just sits there unread. If there's no command there (as in just 1<<<test
), then it certainly won't get read.
FD 1 a bit special, because it's reserved for standard output (stdout). Commands normally don't read from it at all, they write to it. Also, it's normally directed to your terminal device; if you redirect it, that replaces the connection to your terminal, so you're not going to see the output. And since it's now open for reading only, anything that even tries to write to it will run into trouble.
Suppose you run echo "something" 1<<<"test"
, that's essentially:
echo "test" >tempfile
echo "something" 1<tempfile
...so the second echo
command tries to write "something" to stdout (FD 1), but since stdout is a file (or pipe or whatever) that's been opened for reading only (no writing allowed!), its attempt fails and you get "write error: Bad file descriptor" (the error message is sent to FD 2, stderr, so it successfully reaches your terminal).
Now look at your second command, exec 1<<<test
. Again, that's essentially:
echo "test" >tempfile
exec 1<tempfile
The exec
command applies its redirects to the shell (and they're inherited by everything that shell runs). That means the shell and all commands it runs will be trying to send their normal output to a read-only file descriptor, which means almost everything will fail.