Home > Enterprise >  How bash treats Here-docs
How bash treats Here-docs

Time:12-01

I'm working on a modest bash-like shell in C and I have a question on here-doc. For the moment my shell can execute here-doc only in first command.

ls | << eof wc

bash result :

> eof
0 0 0

my result :

> eof
10 10 63

(wc takes the result of ls, I have problem in my pipes but can't figure what.)

In this case, I can just do like ls doesn't exist I think.

wc | << eof wc

bash result

> eof
0 0 0

Here, bash executes the command with here-doc in first and execute the second (which it doesn't has input so it's freezing).

my result

> eof

I execute the here-doc first like bash, and eof works, but I have no result and then it's freezing due to the first wc.

So can I treat all cases like that? I execute the command with here doc first and cancel others except if they have to crash (like wc if it has no input)?

CodePudding user response:

In a POSIX shell, redirections such as here-docs are associated with commands, and the pipe operator (|) separates commands. Thus here:

ls | << eof wc
eof

the here-doc is associated with the second command, wc (even though the redirection operator appears before the command name). It redirects that command's standard input to be from the content of the here-doc. The pipe operator also affects the second command's standard input, so an important question is which effect is applied last, as that is the one that will be effective. POSIX specifies for a pipeline of the form command1 | command2:

The standard output of command1 shall be connected to the standard input of command2. The standard input, standard output, or both of a command shall be considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command.

(Emphasis added.) For what it's worth, the Bash docs say the same in their own words.

For your example, then, the here-doc should replace the output of ls as the input to wc, as it does when Bash processes the command.


In this case, I can just do like ls doesn't exist I think.

wc | << eof wc

bash result

> eof
0 0 0

Here, bash executes the command with here-doc in first and execute the second (which it doesn't has input so it's freezing).

Not exactly. The heredoc belongs to the second wc command, not the first, so it is the first that hangs waiting for interactive input. You can cause that to finish normally by typing a ctrl-D.

More importantly, if the idea is to ignore the ls, then why use two wc commands? Just drop the ls and the pipeline altogether, and use a single wc command:

<<eof wc
eof

# OR, equivalently and more conventionally,

wc <<eof
eof

So can I treat all cases like that? I execute the command with here doc first and cancel others except if they have to crash (like wc if it has no input)?

You seem to be trying to create specific rules where you should instead be observing more general ones. Each command has standard input, output, and error that are initially either inherited from the host shell or assigned as directed by pipe operators. Redirections, including from here-docs, are each part of an individual command, and their effects are applied on top of the initial standard stream assignments for that command. When multiple redirections apply to the same command, they are processed from left to right.

You cannot "cancel" commands based on the status of their standard streams. They will do whatever they do with the streams they receive. That might be nothing at all, terminating with an error, or exactly what they would have done anyway, among other possibilities. The shell doesn't know, so it cannot shortcut this.

  • Related