8

I think I'm having a massive brainfart. I would expect

env foo=bar echo $foo

...to print bar, but I get an empty line instead. Wat.

The same happens if I use the bash syntax:

foo=bar echo $foo
badp
  • 2,977

1 Answers1

8

A similar question was answered recently: the symbols are evaluated in the line before the symbol is defined in this line, making it necessary to split the definition and use of the symbols to separate lines.

Prompted by a comment, you could have done this:

foo=bar bash -c 'echo $foo'

which first assigns a value to foo and passes that into a new process as an environment variable where it can be printed.

You can read more about it in POSIX Shell Command Language Token recognition.

Following up from @mikeserv comment:

  • POSIX is not explicit enough to give the whole answer.
  • At the beginning of the cited section, it says

    The shell shall read its input in terms of lines from a file, from a terminal in the case of an interactive shell, or from a string in the case of sh -c or system().

  • at the end, it says

    Once a token is delimited, it is categorized as required by the grammar in Shell Grammar.

  • but POSIX does not say explicitly that the entire line is tokenized before working on the grammar.
  • in that case, we rely on existing practice - the shell conforms because nothing contradicts the written standard, but the standard cannot be used to predict the behavior in all cases.
  • the same comment applies, of course, to the behavior of aliases (which is why I referred to it as a similar question).
Thomas Dickey
  • 76,765
  • or if you are okay with quoting hell, env foo=bar bash -c 'echo $foo' – badp Nov 09 '15 at 09:49
  • Actually, the alias question relies upon the token-recognition section's implication that tokens are all computed for a given line before moving on to the grammar. But for both, the standard is not explicit, making you rely on existing practice. – Thomas Dickey Nov 09 '15 at 10:12
  • @thomasdickey - yeah, that was my gist too. you know, when you're writing a comment if you do @username...comment the user you specify will get a little message letting them know you were talking to them. well, they will if its thread-relevant. – mikeserv Nov 09 '15 at 10:18
  • @mikeserv (like this). hmm - I'll keep that in mind (though how it works with embedded blanks was not apparent). – Thomas Dickey Nov 09 '15 at 10:25
  • like that. tangentially, i had a look at luit.c and i think i can just change setup_io(){ ... ;fnctl(0, [GS]ETFL, 0);...} to do 2 for the first argument. well, i guess the copyTermios() and setRawTermios() functions might need a little modification as well, but it should be simple, i think. the rc = (return) for every line seems strange - but i'm no C programmer either. is that your thing or was that inherited? and if your blanks comment is referring to "${set_null_var:=new val and $(echo other stuff)}" you're mostly safe w/ anything. some shells will do weird stuff with }. – mikeserv Nov 09 '15 at 10:31
  • The order is quite clearly specified there and there, assignments are only done after expansions in non-redir and non-assignment words have been done. – Stéphane Chazelas Nov 09 '15 at 16:32
  • If it were explicit, the second link would mention that it is an invarying order of steps to be performed, rather than implying it as was done using the wording "general overview of operations". I considered that in my comments earlier, and did not overlook it. – Thomas Dickey Nov 09 '15 at 21:38