First, just to avoid anyone wasting time by pointing it out, to exchange the values of two variables in sh, the following works, and is the safe way to do it
t=$a ; a=$b ; b=$t (then unset t if you want). But using multiple commands isn't always possible, eg: without resorting to explicit sub-shells ('(' ... ')') if one wants to do a=$b b=$a cmd is there any way to make that do what is expected (or perhaps hoped), that can be relied upon to work? That is is one of the following actually specified to work? a=$b b=$a or t=$a a=$b b=$t (that 't' gets set in the second one we can consider irrelevant) XCU 2.9.1.1 says that the var assignments happen left to right, and bullet point 4 in that section says: 4. Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal prior to assigning the value. >From this we know that (in the first of the two cases above) that a is assigned before b, and $b is expanded before $a but does that text actually say that the assignment to a is done before $a is expanded? All it explicitlty says is that the expansions happen before (prior to) when the value is assigned. If one could assume that each assignment is required to happen immediately after expanding its value, before expanding any later values, then the 2nd form above is guaranteed to work. If one could assume that all the assignment words are expanded, left to right, and then once that is done, they are all assigned left to right, then the first form would work instead. But there's even less (some might say no) wording in the standard which suggests that it must work that way. If neither of those is required (by the current wording), then it seems like the standard should be updated - to make one of those be required, or to explicitly state that the behaviour is unspecified in this case. Note that much the same issue occurs with redirects, eg: in exec 3>/my/stderr cmd 3>/some/file 4>$( command 2>&3 ) can one assume that the fd 3 used in the command substitution is the one redirected to /some/file by the earlier redirection, or can we assume that will refer to fd 3 that was previously set up (/my/stderr) or is this also unspecified? Where in the standard can we determine the answer to this question? Note this also probably largely turns on whether expansions in redirections are all performed before any of the actual redirections, or whether each redirect is independently expanded and performed as a unit, before moving on to the next. This all gets messier when here docs are involved cmd <<-EOF 3>/some/file text $( command 2>&3 ) EOF because of the lexical way that here docs are collected, and then later processed, I suspect that not all shells do this kind of thing quite the same way. [Aside: if "command" in the above outputs text starting with tab characters, are those tabs intended to be eliminated along with the tab that precedes the $( ) ? That is, is tab removal (the <<- operator) part of the lexical collection of the here doc text, or is it part of the expansion (when the termination word is unquoted - if it were 'EOF' then there cannot be a command substitution for this to matter). Is this specified anywhere? What XCU 2.7,4 says is: If no part of word is quoted, all lines of the here-document shall be expanded for parameter expansion, command substitution, and arithmetic expansion. In this case, the <backslash> in the input behaves as the <backslash> inside double-quotes (see Section 2.2.3). However, the double-quote character ('"') shall not be treated specially within a here-document, except when the double-quote appears within "$()", "``", or "${}". If the redirection operator is "<<-", all leading <tab> characters shall be stripped from input lines and the line containing the trailing delimiter. The second paragraph (as shown here) is after the first, which might suggest that tab removal happens after the expansions. It also isn't clear from this, that the expansions happen each time the here doc is used as input to some command (and only then) whereas the text of the here doc is (and must be) read as part of lexical processing of the text (it vanishes from the input as seen by the tokeniser). I believe the following is expected to work, and does in all the shells I tested, but I don't see it actually specified anywhere: for var in A B C do cat <<-EOF var is $var $( printf '\tEOF\n' ) done EOF done "works" means prints 3 lines per iteration, 1 with "var is "{A,B,C} (in turn) 2 "EOF" indented (by a tab), and 3 "done". We also know that \newline is ignored in an unquoted-word here doc, but does that happen before or after tab removal cat <<-EOF X \ Y EOF One or two tabs between X and Y in the output? And before or after looking for the terminal word ? cat <<-EOF hello E\ O\ F ??? Or perhaps this one: cat <<-EOF hello\ EOF Or this cat <<-EOF \ EOF Where are the answers to all of this specified? (Specified as unspecified counts.) ] kre