2

I have a case of twisted shell logic to submit to you, since I have found nothing on that particular point anywhere (please accept my apologies if I missed it). I'll try to explain the context as best I can.

I have a first scriptA which I expect to generate a second scriptB through the use of a heredoc. There are two items I want to have in this heredoc: a my_source file include, and some variables local to scriptA (for expansion within scriptA, that is). Here is an example:

scriptA:

#!/bin/sh
logfile=/path/to/my_logfile
scriptB=/path/to/my_script
cat > ${scriptB} << __EOF__
  . /path/to/my_source  #this is a shell script
  echo "Some text" | tee -a ${logfile}
__EOF__

My question on the snippet above is: will shell expansion on the . instruction (i.e. inclusion of my_source) occur in scriptA or in scriptB?

Bonus: is it possible to specify somehow that some part of the here doc should not be expanded?

Note: I tried to be POSIX-compliant here and avoid bash specifics

Thanks for the insights!

EDIT: Answer is that the . utility shall not trigger in the here-doc in scriptA. This is because a here-doc only performs:

parameter expansion, command substitution, and arithmetic expansion

The . is a shell special built-in utility, which is not expanded (just like all shell built-ins, including bash-, ksh-, tcsh-specific (...) built-ins).

Thanks @ilkkachu for the insight.

2 Answers 2

2

No, a here-doc is expanded mostly like a double-quoted string:

If no part of word is quoted, all lines of the here-document shall be expanded for parameter expansion, command substitution, and arithmetic expansion.

Backslashes also work to escape special characters.

The note about quoting means that something like <<"EOF" would prevent expanding anything within the here-doc. In your example, the reference to ${logfile} would be expanded by the shell before passing the input to cat.

You could still use command substitution if you want to include the output of a command, but if all you want is that, using a pipe would also be a logical choice.

3
  • I was assuming the . would fall under the command substitution definition, e.g. expanded before the here-doc creation. Thanks for the quick comment!
    – Meeshkah
    Mar 30, 2017 at 11:36
  • 1
    @Meeshkah, nope. Even though it has an unusual name, it's just a builtin command (strictly speaking, a special built-in utility, but the difference is minor).
    – ilkkachu
    Mar 30, 2017 at 11:50
  • ok I see the difference now, thank you. Can you expand on your suggestion to use a pipe in your OP? I'm not sure I get this 'choice'
    – Meeshkah
    Mar 30, 2017 at 11:57
1

The heredoc doesn't do re-interpretation or you can say, doesn't run any commands inside it. It just interpolates strings.

So the answer to your query is that the source-ing will not happen inside the heredoc.

As for the latter, you can make use of \ i.e., backslashes to turn OFF the meaning of characters you don't want expanded by the heredoc.

2
  • OK, what would happen if I escaped the . command: \. /path/to/my_source? Would the backslash be included in the here-doc b/c the . is not recognized as a command?
    – Meeshkah
    Mar 30, 2017 at 11:38
  • Nothing would happen. The \ would be found attached to the . and that's it. I would urge you to consider the heredoc as a multiline variable being double quote interpolated. (unless there's a \heredoc)
    – user218374
    Mar 30, 2017 at 22:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .