• An interesting little quirk - difference between "bash" and "dash" (Lin

    From Kenny McCormack@21:1/5 to All on Sun Jan 5 12:04:59 2025
    Consider these two command lines (run from a bash shell, but that's
    actually not relevant):

    $ bash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun' In myfun(), foo =
    $ dash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun' In myfun(), foo = bar
    $

    The difference is that in dash, the local foo picks up the value of the
    global foo, while in bash, it is empty.

    I'm not standards obsessed like some people in these newsgroups; I care
    more about desirable functionality. In this case, I would not be surprised
    to hear that the dash behavior is more POSIX-ly correct, but it seems clear
    to me that the bash behavior is more desirable.

    I frequently use "local" precisely to ensure that I get a fresh,
    un-initialized variable. Yes, I know that you can always do: local foo=''
    but that takes the fun out of it.

    --
    BigBusiness types (aka, Republicans/Conservatives/Independents/Liberatarians/whatevers)
    don't hate big government. They *love* big government as a means for them to get
    rich, sucking off the public teat. What they don't like is *democracy* - you know,
    like people actually having the right to vote and stuff like that.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jerry Peters@21:1/5 to Kenny McCormack on Sun Jan 5 20:37:06 2025
    Kenny McCormack <gazelle@shell.xmission.com> wrote:
    Consider these two command lines (run from a bash shell, but that's
    actually not relevant):

    $ bash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo =
    $ dash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo = bar
    $

    The difference is that in dash, the local foo picks up the value of the global foo, while in bash, it is empty.

    I'm not standards obsessed like some people in these newsgroups; I care
    more about desirable functionality. In this case, I would not be surprised to hear that the dash behavior is more POSIX-ly correct, but it seems clear to me that the bash behavior is more desirable.

    I frequently use "local" precisely to ensure that I get a fresh, un-initialized variable. Yes, I know that you can always do: local foo='' but that takes the fun out of it.


    It's optional in bash, see typeset:
    The -I option causes local variables to inherit the
    attributes (except the nameref attribute) and value of any existing
    variable with the same name at a surrounding scope. If there is no
    existing variable, the local variable is ini???
    tially unset.

    That said, I always try to initialize locals if they're not
    unconditionally set in the cide.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Kenny McCormack on Sun Jan 5 20:35:02 2025
    On 2025-01-05, Kenny McCormack <gazelle@shell.xmission.com> wrote:
    Consider these two command lines (run from a bash shell, but that's
    actually not relevant):

    $ bash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo =
    $ dash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo = bar
    $

    The difference is that in dash, the local foo picks up the value of the global foo, while in bash, it is empty.

    I'm not standards obsessed like some people in these newsgroups; I care
    more about desirable functionality. In this case, I would not be surprised to hear that the dash behavior is more POSIX-ly correct, but it seems clear to me that the bash behavior is more desirable.

    I frequently use "local" precisely to ensure that I get a fresh, un-initialized variable.

    From your example we know that it is initialized; we don't know that
    it's not fresh. If dash lets us can assign to the variable, such that
    the global one is affected, then the local means nothing.

    Indeed, there is a fresh binding:

    $ dash -c 'foo=bar; myfun() { local foo; echo $foo; foo=xyzzy; }; myfun; echo $foo'
    bar
    bar

    It's just that if you don't specify an assignment in local, the
    fresh binding inherits the previously visible value.

    In Lisp terms:

    ;; bash semantics:
    (let ((*foo*)) ... fresh binding with nil value)

    ;; dash semantics:
    (let ((*foo* *foo*)) ... fresh binding with same value)

    The second idiom is crops up in Lisp programming quite a bit; it is
    useful to have a fresh binding of a variable which has the current value
    so that any modifications of the variable are rolled back when that
    scope terminates. (Note that the asterisks in *foo* are just part of
    the name; it's the "earmuffs" convention used for naming dynamically
    scoped variables. The scope of let is such that in ((*foo* *foo**)),
    the scope that is visible to the initializing expression is the
    previous one which doesn't yet have the new binding of the variable.

    Obviously, if you want portable code between Bash and Dash,
    you have to initialize your locals.

    Yes, I know that you can always do: local foo=''
    but that takes the fun out of it.

    1. Just local foo= will do.

    2. You can always start your code with #!/bin/bash, and forget about
    Dash. Portability takes fun out of things, especially when things
    have to get ugly or inconvenient.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Waitzmann@21:1/5 to All on Sun Jan 5 22:26:22 2025
    gazelle@shell.xmission.com (Kenny McCormack):
    $ bash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo =
    $ dash -c 'foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun'
    In myfun(), foo = bar
    $

    The difference is that in dash, the local foo picks up the value of the global foo, while in bash, it is empty.

    I'm not standards obsessed like some people in these newsgroups; I care
    more about desirable functionality. In this case, I would not be surprised to hear that the dash behavior is more POSIX-ly correct,


    I guess, you won't be surprised to read that neither the bash nor
    the dash behavior is part of the POSIX standard.


    but it seems clear to me that the bash behavior is more
    desirable.

    I frequently use "local" precisely to ensure that I get a fresh, un-initialized variable.

    Bash won't give you an un‐initialized variable.  It will give you
    an modified, emptied variable, while dash will give you an
    unmodified variable.


    By the way, neither behavior will give you a fresh variable.  Try


    (
    for shell in bash dash
    do
    printf '\n%s:\n' "$shell"
    "$shell" -c '
    foo=bar && readonly -- foo &&
    myfun()
    {
    local foo
    printf "In myfun(), foo = %s\n" "$foo"
    foo=
    } &&
    myfun' "$shell"
    done
    )

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Weisgerber@21:1/5 to Kenny McCormack on Sun Jan 5 20:27:59 2025
    On 2025-01-05, Kenny McCormack <gazelle@shell.xmission.com> wrote:

    foo=bar;myfun() { local foo; echo "In myfun(), foo = $foo"; };myfun

    I'm not standards obsessed like some people in these newsgroups; I care
    more about desirable functionality. In this case, I would not be surprised to hear that the dash behavior is more POSIX-ly correct,

    Surprisingly, "local" isn't part of the POSIX shell language at all.

    Its only mention is under "If the command name matches the name of
    a utility listed in the following table, the results are unspecified".

    Is there any POSIX-y shell that does not implement "local"?

    --
    Christian "naddy" Weisgerber naddy@mips.inka.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Christian Weisgerber on Mon Jan 6 01:23:11 2025
    On 05.01.2025 21:27, Christian Weisgerber wrote:

    Surprisingly, "local" isn't part of the POSIX shell language at all.

    [...]

    Is there any POSIX-y shell that does not implement "local"?

    In Kornshell variable-attributes/properties are regularly specified
    using 'typeset' and thus the 'typeset' keyword is also used to create function-"local" variables.

    There's no 'local' keyword in Kornshell, and there's also no alias of
    that name defined for 'typeset'[*].

    Janis

    [*] As opposed to the predefined aliases
    nameref='typeset -n'
    integer='typeset -i'
    float='typeset -E'
    etc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)