I'm trying to wrap my head around how heredocs function in shell scripting, specifically the difference in behavior between redirection and command substitution. In the first example, where I'm redirecting output to `heredoc.txt`, the redirection happens right away on the opening line. However, in the second example, with command substitution, the closing seems to happen only after I finish the heredoc. I'm confused about why the command substitution doesn't terminate on the same line as the heredoc opening command, similar to redirection. I also don't get why this syntax doesn't work, where I close the command substitution on the same line as the heredoc opener. Can anyone help clarify?
6 Answers
Bash structures its execution order before running commands. In the first example, it goes: 1) parse command, 2) set up redirection, 3) execute cat with heredoc. In the second, it’s slightly different because it parses the subcommand first. The key difference is when the stdout is handled.
Honestly, both methods work fine for me except the second one removes newline characters, which is a bit off. Could you explain that?
The key here is the delimiter! In a heredoc, the literal delimiter indicates to the shell where the heredoc ends. If there's anything after your delimiter, like a space or a redirection operator, it won't match the actual delimiter. That’s why structure matters so much during parsing.
You're right! It’s all about how the shell processes the input and identifies where the heredoc really ends.
Also, just a note that 'EOL' isn't a reserved word; you can name your delimiters anything you want, like 'RABBIT', and it will work the same way!
What's confusing about this? Remember, your heredoc resides inside the command substitution. The start of the heredoc has to come after the `<<` token, allowing for redirections in that command. If you have multiple file handles, you can use different heredocs, but they must follow the order they were opened in.
The behaviors are actually consistent! In the first, you're using input redirection with output redirection to a file. In the second example, you’re placing the result into a variable; here, command substitution just replaces the command with its output at the end, which is why closing it on the same line doesn’t work.

Got it, that makes sense! So, the delimiter must stand alone to be recognized properly.