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

  • shell: swapping v... Robert Elz via austin-group-l at The Open Group
    • Re: shell: s... Geoff Clare via austin-group-l at The Open Group
    • Re: shell: s... Robert Elz via austin-group-l at The Open Group
      • Re: shel... Harald van Dijk via austin-group-l at The Open Group
      • Re: shel... Geoff Clare via austin-group-l at The Open Group
      • Re: shel... Robert Elz via austin-group-l at The Open Group
        • Re: ... G. Branden Robinson via austin-group-l at The Open Group
        • Re: ... Robert Elz via austin-group-l at The Open Group
        • Re: ... Geoff Clare via austin-group-l at The Open Group
        • Re: ... Robert Elz via austin-group-l at The Open Group
          • ... Geoff Clare via austin-group-l at The Open Group

Reply via email to