• Re: Variable var names

    From Geoff Clare@geoff@clare.See-My-Signature.invalid to comp.unix.shell on Fri Jun 12 13:42:45 2026
    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>
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Fri Jun 12 15:19:17 2026
    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
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Fri Jun 12 17:41:51 2026
    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="  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

  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Fri Jun 12 17:54:17 2026
    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.)

      x=( "" "  ok  " "  not ok  " )
      echo ${x[1]}
      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

      ( 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="  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


  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 00:20:51 2026
    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 you’re using eval, that’s often a good sign you’re doing something wrong†.

    If you want indirect variable references, bash has “declare -n” for
    that purpose.

    †Except in Lisp. Because Lisp “eval” isn’t evaluating strings, but homoiconic list structures. There’s a lesson in there for other
    languages that naïvely try to copy the concept.
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 02:48:50 2026
    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.
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sat Jun 13 02:51:23 2026
    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 it’s the best behaviour, but because
    it’s 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 “special” or “regular” built-in?
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Sat Jun 13 12:29:31 2026
    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
  • From Frank Winkler@usenet@f.winkler-ka.de to comp.unix.shell on Sat Jun 13 12:32:52 2026

    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
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.unix.shell on Sat Jun 13 11:14:39 2026
    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
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Sat Jun 13 13:15:36 2026
    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
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.unix.shell on Sun Jun 14 01:12:27 2026
    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 don’t try to do *everything* with it ...
  • From Kaz Kylheku@046-301-5902@kylheku.com to comp.unix.shell on Tue Jun 23 21:25:49 2026
    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
  • From Helmut Waitzmann@nn.throttle@erine.email to comp.unix.shell on Wed Jun 24 10:45:52 2026
    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.  In my Debian Linux system, “bash”
    + 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 “sh”:  The “bash” 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
  • From Christian Weisgerber@naddy@mips.inka.de to comp.unix.shell on Wed Jun 24 11:41:31 2026
    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