• Variable var names

    From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Fri Jun 12 09:30:16 2026
    From Newsgroup: comp.unix.shell

    Hi there !

    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1=" ok "
    $ x2=" not ok "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted"
    here? I also tried some variants with "printf", but also with no success.

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    . not ok .
    $

    To my surprise, it works but why is IFS relevant here? And to my even
    bigger surprise, it looks like everything seems to behave as expected in
    the bash session but in the ksh script, IFS is not just changed for this single command but globally - so I had to save and restore it to prevent
    the whole script from exploding. This makes the interesting part much
    longer and more complicated, eating up the potential advantage and
    coolness superiority over just doing something like

    [ $n -eq 1 ] && echo "$x1"
    [ $n -eq 2 ] && echo "$x2"

    Any hints from the experts?

    TIA

    Frank

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.unix.shell on Fri Jun 12 09:02:31 2026
    From Newsgroup: comp.unix.shell

    In article <n91qs8Fk65fU1@mid.individual.net>,
    Frank Winkler <usenet@f.winkler-ka.de> wrote:
    Hi there !

    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1=" ok "
    $ x2=" not ok "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted" >here? I also tried some variants with "printf", but also with no success.

    I don't know much about ksh, but in bash, you can (and, IMHO, you should)
    use the "nameref" functionality.

    I just did:

    $ declare -n foo
    $ n=1;x1=" ok ";x2=" not ok "
    $ for foo in x$n;do echo "|$foo|";done
    | ok |
    $ ((n++));for foo in x$n;do echo "|$foo|";done
    | not ok |
    $

    Note that you have to use a "for" loop to get around a bit of the weirdness
    of how namerefs work in bash.

    I think both "eval" and "IFS" should be avoided if at all possible.
    Too many gotchas associated with both of these constructs.
    --
    There are many self-professed Christians who seem to think that because
    they believe in Jesus' sacrifice they can reject Jesus' teachings about
    how we should treat others. In this country, they show that they reject
    Jesus' teachings by voting for Republicans.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.unix.shell on Fri Jun 12 11:26:07 2026
    From Newsgroup: comp.unix.shell

    Frank Winkler <usenet@f.winkler-ka.de> wrote or quoted:
    So the variable var name seems to work but why are the blanks "deleted" >here?

    Just on --03-15, I wrote here:

    |Nuno Silva <nunojsilva@invalid.invalid> writes:
    -2One last note: echo itself will mangle leading spaces,
    |
    |When you input "echo $x", the shell substitutes "$x" by the value of
    |x with leading and trailing spaces stripped. The shell, not echo!

    .


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.unix.shell on Fri Jun 12 11:38:57 2026
    From Newsgroup: comp.unix.shell

    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    |When you input "echo $x", the shell substitutes "$x" by the value of
    |x with leading and trailing spaces stripped. The shell, not echo!

    Using bash on trixie, I get

    $x=" a "
    $echo $x
    a

    $echo "$x"
    a

    $echo ".$x."
    . a .

    $eval echo \$x
    a

    $eval echo "\$x"
    a

    $eval echo ".\$x."
    . a .

    . So, the behavior of IFS probably is due to the dots "." used.


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Fri Jun 12 14:07:41 2026
    From Newsgroup: comp.unix.shell

    On 12.06.2026 13:38, Stefan Ram wrote:

    >> |x with leading and trailing spaces stripped. The shell, not echo!

    Sure - and that's why I also quoted the variable, which should keep the
    blanks - shouldn't it?

    > . So, the behavior of IFS probably is due to the dots "." used.
    No, it's not. I just added the dots here to clarify that the blanks get
    lost.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Christian Weisgerber@naddy@mips.inka.de to comp.unix.shell on Fri Jun 12 12:12:47 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-12, Frank Winkler <usenet@f.winkler-ka.de> wrote:

    $ n=1
    $ x1=" ok "
    $ x2=" not ok "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted" here?

    The usual expansion, quote stripping, etc. happen, producing

    echo $x1
    echo $x2

    which are then evaluated again. You need to quote the quote
    characters so they make it to the second round:

    $ eval echo \"\$x$n\"
    not ok

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    . not ok .
    $

    To my surprise, it works but why is IFS relevant here?

    The result of substituting $x2 is subject to field splitting according
    to the input field separators (IFS).

    And to my even bigger surprise, it looks like everything seems
    to behave as expected in the bash session but in the ksh script,
    IFS is not just changed for this single command but globally -

    The latter is actually the POSIX-mandated behavior: "If the command
    name is a special built-in utility, variable assignments shall
    affect the current execution environment before the utility is
    executed and remain in effect when the command completes".

    Bash chooses to violate this, unless invoked with --posix or
    POSIXLY_CORRECT.

    The key term here is _special built-in_, as opposed to regular
    built-ins. The POSIX list of special built-ins is
    break, :, continue, ., eval, exec, exit, export, readonly,
    return, set, shift, times, trap, unset
    --
    Christian "naddy" Weisgerber naddy@mips.inka.de
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.unix.shell on Fri Jun 12 12:31:20 2026
    From Newsgroup: comp.unix.shell

    Frank Winkler <usenet@f.winkler-ka.de> wrote or quoted:
    . So, the behavior of IFS probably is due to the dots "." used.
    No, it's not. I just added the dots here to clarify that the blanks get >lost.

    Sorry, I misread the whole IFS line.

    Now, I tried,

    $ x=" a "

    $ eval echo "\$x"
    a

    $ IFS="" eval echo \$x
    a

    . When the shell executes 'echo $x' after the input 'eval echo "\$x"',
    the quotes were already stripped during the preceding shell expansion.
    So, eval sees an unquoted '$x'. In evaluation of 'echo $x' by eval,
    word splitting happens, which removes the blanks.

    But when IFS is empty, no word splitting happens.

    |Word splitting begins by removing sequences of IFS whitespace
    |characters from the beginning and end of the results of the
    |previous expansions
    Word Splitting (Bash Reference Manual)

    |When IFS is empty (nullstring), no word splitting is
    |performed at all.
    Word splitting - The Bash Hackers Wiki


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Geoff Clare@geoff@clare.See-My-Signature.invalid to comp.unix.shell on Fri Jun 12 13:42:45 2026
    From Newsgroup: comp.unix.shell

    Frank Winkler wrote:

    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1=" ok "
    $ x2=" not ok "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted" here?

    After eval interprets:

    eval echo "\$x$n"

    the command to be executed by the shell (with n=1) is:

    echo $x1

    In order to quote the argument passed to echo, you need to supply
    some quotes that will survive the parsing that eval does:

    $ n=1
    $ x1=" ok "
    $ eval echo "\"\$x$n\""
    ok

    Here the command to be executed by the shell is:

    echo "$x1"

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    . not ok .
    $

    To my surprise, it works but why is IFS relevant here?

    Hopefully you can see why now, given the extra quotes in my example above.

    And to my even
    bigger surprise, it looks like everything seems to behave as expected in
    the bash session but in the ksh script, IFS is not just changed for this single command but globally - so I had to save and restore it to prevent
    the whole script from exploding.

    This is actually required by POSIX. If you set POSIXLY_CORRECT=1 in
    the environment, bash does the same. (It's required for the "special
    built-in utilities", of which eval is one.)
    --
    Geoff Clare <netnews@gclare.org.uk>
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Fri Jun 12 15:19:17 2026
    From Newsgroup: comp.unix.shell

    On 12.06.2026 14:12, Christian Weisgerber wrote:

    >which are then evaluated again. You need to quote the quote
    >characters so they make it to the second round:
    >
    >$ eval echo \"\$x$n\"
    > not ok

    You're absolutely right - I really (sh|c)ould have had this idea by
    myself ;) ...

    >The result of substituting $x2 is subject to field splitting according
    >to the input field separators (IFS).

    Thanks for waking me up, Christian! :)

    >The latter is actually the POSIX-mandated behavior: "If the command
    >name is a special built-in utility, variable assignments shall
    >affect the current execution environment before the utility is
    >executed and remain in effect when the command completes".
    >
    >Bash chooses to violate this, unless invoked with --posix or
    POSIXLY_CORRECT.

    Thanks for that info - I wasn't aware of that!

    Regards

    Frank

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Fri Jun 12 17:41:51 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-12 09:30, Frank Winkler wrote:
    Hi there !

    You've already got a couple useful hints and explanations. So just
    some additional hints...

    Below, consider using arrays instead of manipulating variable names.
    (Thereby you avoid the 'eval' that you've already been suggested to
    avoid in the first place, if not really necessary.)

    x=( "" " ok " " not ok " )
    echo ${x[1]}
    echo ${x[2]}

    Standard arrays are counted from 0 so the first array element has
    a dummy element above. (Modern shells also support associative
    arrays, in case you want more flexibility.)

    If you want for (some reason) to use 'eval' note that you can, as
    suggested, use two layers of quotes (one escaped), or just use two
    different nested quotes ( " and ' ), but also note the effects of
    expansions inside the double-quotes; you can take that for your
    advantage (if you know the expansion rules).

    The effect of IFS changes on _internal_ shell commands like 'eval'
    have been explained already, and that this is standard behavior.
    Note that you don't need to save/restore the IFS in standard code;
    you can also embed it in a subshell-environment with parenthesis
    to keep the IFS change local within the parenthesis, as in

    ( IFS="" eval echo ".\$x$n." )

    In ksh you won't create a real subshell that way if there's only
    shell built-ins like 'eval' and 'echo' used, so it's efficient.

    If you intend to use mainly "modern" shells like bash, ksh, zsh,
    you should consider using (instead of [ ... ]) [[ ... ]], or in
    case of arithmetic (as in your code below) the shell's arithmetic
    statement

    (( n == 1 )) && ..

    For many values you may also use 'case',

    case $n in
    (1) ... ;;
    (2) ... ;;
    (*) ... ;; # default branch for errors
    esac

    And of course use 'printf' (instead of 'echo').

    Janis


    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1="-a ok-a "
    $ x2="-a not ok-a "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted" here? I also tried some variants with "printf", but also with no success.

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    .-a not ok-a .
    $

    To my surprise, it works but why is IFS relevant here? And to my even
    bigger surprise, it looks like everything seems to behave as expected in
    the bash session but in the ksh script, IFS is not just changed for this single command but globally - so I had to save and restore it to prevent
    the whole script from exploding. This makes the interesting part much
    longer and more complicated, eating up the potential advantage and
    coolness superiority over just doing something like

    -a [ $n -eq 1 ] && echo "$x1"
    -a [ $n -eq 2 ] && echo "$x2"

    Any hints from the experts?

    TIA

    -a-a-a-aFrank


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Fri Jun 12 17:54:17 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-12 17:41, Janis Papanagnou wrote:
    On 2026-06-12 09:30, Frank Winkler wrote:
    Hi there !

    You've already got a couple useful hints and explanations. So just
    some additional hints...

    Below, consider using arrays instead of manipulating variable names.
    (Thereby you avoid the 'eval' that you've already been suggested to
    avoid in the first place, if not really necessary.)

    -a x=( "" "-a ok-a " "-a not ok-a " )
    -a echo ${x[1]}
    -a echo ${x[2]}

    And of course I forgot to mention (and also consider above) the most
    basic rule; quote your variables. Above should of course have been

    echo "${x[1]}"
    echo "${x[2]}"

    (and 'echo' also replaced by 'printf', of course). :-)


    Standard arrays are counted from 0 so the first array element has
    a dummy element above. (Modern shells also support associative
    arrays, in case you want more flexibility.)

    If you want for (some reason) to use 'eval' note that you can, as
    suggested, use two layers of quotes (one escaped), or just use two
    different nested quotes ( " and ' ), but also note the effects of
    expansions inside the double-quotes; you can take that for your
    advantage (if you know the expansion rules).

    The effect of IFS changes on _internal_ shell commands like 'eval'
    have been explained already, and that this is standard behavior.
    Note that you don't need to save/restore the IFS in standard code;
    you can also embed it in a subshell-environment with parenthesis
    to keep the IFS change local within the parenthesis, as in

    -a ( IFS="" eval echo ".\$x$n." )

    In ksh you won't create a real subshell that way if there's only
    shell built-ins like 'eval' and 'echo' used, so it's efficient.

    If you intend to use mainly "modern" shells like bash, ksh, zsh,
    you should consider using (instead of [ ... ]) [[ ... ]], or in
    case of arithmetic (as in your code below) the shell's arithmetic
    statement

    -a (( n == 1 )) && ..

    For many values you may also use 'case',

    -a case $n in
    -a (1) ... ;;
    -a (2) ... ;;
    -a (*) ... ;;-a # default branch for errors
    -a esac

    And of course use 'printf' (instead of 'echo').

    Janis


    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1="-a ok-a "
    $ x2="-a not ok-a "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks
    "deleted" here? I also tried some variants with "printf", but also
    with no success.

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    .-a not ok-a .
    $

    To my surprise, it works but why is IFS relevant here? And to my even
    bigger surprise, it looks like everything seems to behave as expected
    in the bash session but in the ksh script, IFS is not just changed for
    this single command but globally - so I had to save and restore it to
    prevent the whole script from exploding. This makes the interesting
    part much longer and more complicated, eating up the potential
    advantage and coolness superiority over just doing something like

    -a-a [ $n -eq 1 ] && echo "$x1"
    -a-a [ $n -eq 2 ] && echo "$x2"

    Any hints from the experts?

    TIA

    -a-a-a-a-aFrank



    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 00:20:51 2026
    From Newsgroup: comp.unix.shell

    On Fri, 12 Jun 2026 09:30:16 +0200, Frank Winkler wrote:

    To my surprise, it works but why is IFS relevant here? And to my
    even bigger surprise, it looks like everything seems to behave as
    expected in the bash session but in the ksh script, IFS is not just
    changed for this single command but globally - so I had to save and
    restore it to prevent the whole script from exploding.

    If yourCOre using eval, thatrCOs often a good sign yourCOre doing something wrongrCa.

    If you want indirect variable references, bash has rCLdeclare -nrCY for
    that purpose.

    rCaExcept in Lisp. Because Lisp rCLevalrCY isnrCOt evaluating strings, but homoiconic list structures. ThererCOs a lesson in there for other
    languages that na|>vely try to copy the concept.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 02:48:50 2026
    From Newsgroup: comp.unix.shell

    On 12 Jun 2026 12:31:20 GMT, Stefan Ram wrote:

    Word splitting - The Bash Hackers Wiki

    Remember that every command gets, not a simple string, but an array of
    strings as its arguments. This applies to shell builtin commands as
    well.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 02:51:23 2026
    From Newsgroup: comp.unix.shell

    On Fri, 12 Jun 2026 12:12:47 -0000 (UTC), Christian Weisgerber wrote:

    The latter is actually the POSIX-mandated behavior: "If the command
    name is a special built-in utility, variable assignments shall
    affect the current execution environment before the utility is
    executed and remain in effect when the command completes".

    Sometimes, you must remember, a standard like POSIX has to codify
    existing behaviour, not because itrCOs the best behaviour, but because
    itrCOs the most common behaviour (or the common behaviour among products
    from companies which are/were the biggest marketing heavyweights at
    the time).

    Bash chooses to violate this, unless invoked with --posix or
    POSIXLY_CORRECT.

    Because who can remember the difference between a rCLspecialrCY or rCLregularrCY built-in?
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Sat Jun 13 12:29:31 2026
    From Newsgroup: comp.unix.shell

    On 12.06.2026 11:02, Kenny McCormack wrote:

    >I don't know much about ksh, but in bash, you can (and, IMHO, you should)
    >use the "nameref" functionality.

    I'm still trying to figure out how exactly that works ... ut thanks for
    the hint!

    Frank

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Sat Jun 13 12:32:52 2026
    From Newsgroup: comp.unix.shell


    Many thanks also to all the other guys who provided useful stuff.
    Besides some "easy ones" I accidentally didn't think to an end, there
    were a couple of really new insights ;) ...

    Shell scripting is still a cool science of its own :) ...

    Regards

    Frank

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.unix.shell on Sat Jun 13 11:14:39 2026
    From Newsgroup: comp.unix.shell

    In article <n94pobF3vrqU1@mid.individual.net>,
    Frank Winkler <usenet@f.winkler-ka.de> wrote:
    On 12.06.2026 11:02, Kenny McCormack wrote:

    I don't know much about ksh, but in bash, you can (and, IMHO, you should)
    use the "nameref" functionality.

    I'm still trying to figure out how exactly that works ... but thanks for
    the hint!

    It *is* tricky and unintuitive in many ways, but it can be handy, once you
    get familiar with it.

    Note, BTW, that I chose to focus on the "Variable var names" aspect of your original post (that which is actually mentioned in the Subject: line),
    while most of the other responders have focussed on the "What happened to
    my leading and trailing blanks?" aspect of it. I consider that later aspect
    to be trivial and just a simple lack of understanding and care about shell quoting on your part.
    --
    The randomly chosen signature file that would have appeared here is more than 4-ish
    lines long. As such, it violates one or more Usenet RFCs. In order to remain in compliance with said RFCs, the actual sig can be found at the following URL:
    http://user.xmission.com/~gazelle/Sigs/BestCLCPostEver
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Sat Jun 13 13:15:36 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-13 12:29, Frank Winkler wrote:
    On 12.06.2026 11:02, Kenny McCormack wrote:

    I don't know much about ksh, but in bash, you can (and, IMHO, you should)
    use the "nameref" functionality.

    I'm still trying to figure out how exactly that works ... ut thanks for
    the hint!

    With ksh93 Kornshell introduced "namerefs" as 'typeset -n' or as
    alias 'nameref' as alternate form. They were mainly introduced to
    support the concept of _reference parameters_ for functions.

    function change_it
    {
    nameref one=$1 # arg1 is a variable (reference) name
    one="new value"
    }

    var="old value"
    change_it var # pass a variable name as reference
    echo $var

    Above the 'var' passed to the function can be changed within the
    function if the respective argument is declared as reference.
    Within the function you use the reference name but actually the
    function operates on the variable whose name has been provided
    with the function call. That way you can use the same function
    to change various variables (and does not require to use an own
    [unsafe] 'eval'-based mechanism to emulate such a functionality.)

    Janis

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sun Jun 14 01:12:27 2026
    From Newsgroup: comp.unix.shell

    On Sat, 13 Jun 2026 12:32:52 +0200, Frank Winkler wrote:

    Shell scripting is still a cool science of its own :) ...

    Just so long as you donrCOt try to do *everything* with it ...
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Kaz Kylheku@046-301-5902@kylheku.com to comp.unix.shell on Tue Jun 23 21:25:49 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-12, Frank Winkler <usenet@f.winkler-ka.de> wrote:
    Hi there !

    I'm playing with the following in an interactive bash as well as in a
    ksh script:

    $ n=1
    $ x1=" ok "
    $ x2=" not ok "
    $ eval echo \$x$n
    ok
    $ eval echo "\$x$n"
    ok
    $ n=2
    $ eval echo "\$x$n"
    not ok
    $

    So the variable var name seems to work but why are the blanks "deleted" here? I also tried some variants with "printf", but also with no success.

    eval takes all of its arguments, and catenates them together as if by
    spaces. The resulting string is a piece of shell syntax that is
    lexically scanned and otherwise processed entirely from scratch, almost
    as if the shell were reading input from the command line or a script
    file.

    First your arguments undergo substitutions, producing the arguments
    for eval, like this:

    echo \$x$n -> echo $x1

    echo "\$x$n" -> echo $x2 # n was reassigned to 2

    As you can see, the quoting disappears at this stage before eval
    sees it! In both cases, eval sees the two pieces {echo} and {$x}.
    These are turned into the syntax {echo $x}. This syntax is then
    evaluated. Note that it has no quoting that would preserve
    the blanks in the value of $x.

    Note how you carefully preserved the dollar sign with a backslash
    so that it is not swallowed by the first round of expansions.
    You ensured that eval sees the dollar sign in $x1 and $x2.

    In exactly the same manner, you must insert quoting in such a
    way that it is preserved, for instance like this:

    eval echo \"\$x$n\"

    Now our first round of expansion, before eval is called
    goes like this:

    echo \"\$x$n\" -> echo "$x1"

    That is the correct syntax for echoing x1 with the spaces preserved.

    Just out of curiosity, I tried this:

    $ IFS="" eval echo ".\$x$n."
    . not ok .
    $

    To my surprise, it works but why is IFS relevant here? And to my even

    IFS="" does not kick in until eval executes. The syntax that is produced
    is

    echo .$x2.

    With the default IFS, that would be subject to field spltting,
    producing the four fields {.}{not}{ok}{.} which become separate
    arguments of echo.

    You've overriden IFS over the execution of eval, suppressing that field splitting, so the expansion of .$x2. is taken as-is, a single argument, containing spaces.

    The value of IFS is relevant to the eval, because eval performs complete processing of the syntax from scratch, including another round of
    parameter expansion that takes place before echo is called. (Of course:
    without that expansion we would not get the $x2 interpolation).
    IFS speaks to the semantics of that parameter expansion.

    bigger surprise, it looks like everything seems to behave as expected in
    the bash session but in the ksh script, IFS is not just changed for this single command but globally - so I had to save and restore it to prevent
    the whole script from exploding.

    You've run into a quirk of the VAR=value ... command ... syntax.

    When you use that with an external command, like "CFLAGS=-O2 make",
    it creates an environment binding over just that command. This is
    a widely used, standardized feature that works "everywhere".

    However, when VAR=value it is used on built-in commands, there are
    pitfalls. It depends on which exact built-in command and what shell.

    What the POSIX standard requires in regard to assignments in a command
    can be found here:

    https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html
    in section "2.9.1.2 Variable Assignments".

    As you can see, even in the case when the command is not a built-in
    or function, there are some unspecified behaviors!

    It is also written that "If the command name is a special built-in
    utility, variable assignments shall affect the current execution
    environment before the utility is executed and remain in effect when the command completes". So in fact ksh is conforming, even though it
    is arguably a dumb behavior that Bash disagrees with (even in --posix
    mode; just tested with 4.4 and 5.1).
    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Helmut Waitzmann@nn.throttle@erine.email to comp.unix.shell on Wed Jun 24 10:45:52 2026
    From Newsgroup: comp.unix.shell

    Kaz Kylheku <046-301-5902@kylheku.com>:
    It is also written that "If the command name is a special
    built-in utility, variable assignments shall affect the current
    execution environment before the utility is executed and remain
    in effect when the command completes". So in fact ksh is
    conforming, even though it is arguably a dumb behavior that Bash
    disagrees with (even in --posix mode; just tested with 4.4 and
    5.1).

    Interesting.-a In my Debian Linux system, rCLbashrCY
    + bash --version
    GNU bash, version 5.1.4(1)-release (i686-pc-linux-gnu)
    Copyright (C) 2020 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software; you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    obeys the POSIX standard in --posix mode as well as when invoked
    with the name rCLshrCY:-a The rCLbashrCY command
    (
    cmdline='
    unset -v foo &&
    foo=bar eval : &&
    if ${foo+:} false
    then
    printf %s\\n posixly
    else
    printf %s\\n not\ posixly
    fi' &&
    for invocation in \
    "$(
    printf ' %q' \
    exec -a bash -- bash -c "$cmdline" bash
    )" \
    "$(
    printf ' %q' \
    exec -a bash -- bash --posix -c "$cmdline" bash
    )" \
    "$(
    printf ' %q' \
    exec -a sh -- bash -c "$cmdline" sh
    )"
    do
    eval set -- "$invocation" && echo &&
    ( set -x && "$@" )
    done
    )
    yields the following output:
    + exec -a bash -- bash -c '
    unset -v foo &&
    foo=bar eval : &&
    if ${foo+:} false
    then
    printf %s\\n posixly
    else
    printf %s\\n not\ posixly
    fi' bash
    not posixly
    + exec -a bash -- bash --posix -c '
    unset -v foo &&
    foo=bar eval : &&
    if ${foo+:} false
    then
    printf %s\\n posixly
    else
    printf %s\\n not\ posixly
    fi' bash
    posixly
    + exec -a sh -- bash -c '
    unset -v foo &&
    foo=bar eval : &&
    if ${foo+:} false
    then
    printf %s\\n posixly
    else
    printf %s\\n not\ posixly
    fi' sh
    posixly
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Christian Weisgerber@naddy@mips.inka.de to comp.unix.shell on Wed Jun 24 11:41:31 2026
    From Newsgroup: comp.unix.shell

    On 2026-06-23, Kaz Kylheku <046-301-5902@kylheku.com> wrote:

    It is also written that "If the command name is a special built-in
    utility, variable assignments shall affect the current execution
    environment before the utility is executed and remain in effect when the command completes". So in fact ksh is conforming, even though it
    is arguably a dumb behavior that Bash disagrees with (even in --posix
    mode; just tested with 4.4 and 5.1).

    $ bash -c 'foo=bar eval : ; echo x$foo'
    x
    $ bash --posix -c 'foo=bar eval : ; echo x$foo'
    xbar
    $ bash -c 'echo $BASH_VERSION'
    5.3.15(0)-release
    --
    Christian "naddy" Weisgerber naddy@mips.inka.de
    --- Synchronet 3.22a-Linux NewsLink 1.2