List of shells that support `local` keyword for defining local variables












1















I know that Bash and Zsh support local variables, but there are systems only have POSIX-compatible shells. And local is undefined in POSIX shells.



So I want to ask which shells support local keyword for defining local variables?



Edit: About shells I mean the default /bin/sh shell.










share|improve this question




















  • 1





    dash supports them, ksh supports them but I think you need to use typeset instead of local

    – Jesse_b
    Jan 10 at 14:18






  • 3





    @Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

    – pizdelect
    Jan 10 at 14:21













  • @pizdelect: thanks for reiterating exactly what I just said

    – Jesse_b
    Jan 10 at 14:23








  • 1





    @Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

    – pizdelect
    Jan 10 at 14:24








  • 1





    @Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

    – Stephen Kitt
    Jan 10 at 15:51
















1















I know that Bash and Zsh support local variables, but there are systems only have POSIX-compatible shells. And local is undefined in POSIX shells.



So I want to ask which shells support local keyword for defining local variables?



Edit: About shells I mean the default /bin/sh shell.










share|improve this question




















  • 1





    dash supports them, ksh supports them but I think you need to use typeset instead of local

    – Jesse_b
    Jan 10 at 14:18






  • 3





    @Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

    – pizdelect
    Jan 10 at 14:21













  • @pizdelect: thanks for reiterating exactly what I just said

    – Jesse_b
    Jan 10 at 14:23








  • 1





    @Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

    – pizdelect
    Jan 10 at 14:24








  • 1





    @Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

    – Stephen Kitt
    Jan 10 at 15:51














1












1








1








I know that Bash and Zsh support local variables, but there are systems only have POSIX-compatible shells. And local is undefined in POSIX shells.



So I want to ask which shells support local keyword for defining local variables?



Edit: About shells I mean the default /bin/sh shell.










share|improve this question
















I know that Bash and Zsh support local variables, but there are systems only have POSIX-compatible shells. And local is undefined in POSIX shells.



So I want to ask which shells support local keyword for defining local variables?



Edit: About shells I mean the default /bin/sh shell.







shell-script shell






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 5 mins ago









Stéphane Chazelas

303k56570924




303k56570924










asked Jan 10 at 14:13









mjamja

302213




302213








  • 1





    dash supports them, ksh supports them but I think you need to use typeset instead of local

    – Jesse_b
    Jan 10 at 14:18






  • 3





    @Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

    – pizdelect
    Jan 10 at 14:21













  • @pizdelect: thanks for reiterating exactly what I just said

    – Jesse_b
    Jan 10 at 14:23








  • 1





    @Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

    – pizdelect
    Jan 10 at 14:24








  • 1





    @Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

    – Stephen Kitt
    Jan 10 at 15:51














  • 1





    dash supports them, ksh supports them but I think you need to use typeset instead of local

    – Jesse_b
    Jan 10 at 14:18






  • 3





    @Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

    – pizdelect
    Jan 10 at 14:21













  • @pizdelect: thanks for reiterating exactly what I just said

    – Jesse_b
    Jan 10 at 14:23








  • 1





    @Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

    – pizdelect
    Jan 10 at 14:24








  • 1





    @Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

    – Stephen Kitt
    Jan 10 at 15:51








1




1





dash supports them, ksh supports them but I think you need to use typeset instead of local

– Jesse_b
Jan 10 at 14:18





dash supports them, ksh supports them but I think you need to use typeset instead of local

– Jesse_b
Jan 10 at 14:18




3




3





@Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

– pizdelect
Jan 10 at 14:21







@Jesse_b ksh doesn't support the local keyword; it does support local variables, but via typeset not via the local, and only in funcs defined as function foo { }, not in funcs defined as foo(){ }.

– pizdelect
Jan 10 at 14:21















@pizdelect: thanks for reiterating exactly what I just said

– Jesse_b
Jan 10 at 14:23







@pizdelect: thanks for reiterating exactly what I just said

– Jesse_b
Jan 10 at 14:23






1




1





@Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

– pizdelect
Jan 10 at 14:24







@Jesse_b did you miss the part about typeset not working in functions defined as foo(){ ... }? Example: foo(){ typeset v=3; }; function bar { typeset v=7; }; v=1; foo; echo $v; bar; echo $v; => 3, 3.

– pizdelect
Jan 10 at 14:24






1




1





@Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

– Stephen Kitt
Jan 10 at 15:51





@Jesse_b I’ve seen many AIX systems without bash, even new ones set up last year.

– Stephen Kitt
Jan 10 at 15:51










2 Answers
2






active

oldest

votes


















7














It's not as simple as supporting local or not. There is a lot of variation on the syntax and how it's done between shells that have one form or other of local scope.



That's why it's very hard to come up with a standard that agrees with all. See http://austingroupbugs.net/bug_view_page.php?bug_id=767 for the POSIX effort on that front.



local scope was added first in ksh in the early 80s.



The syntax to declare a local variable in a function was with typeset:



function f {
typeset var=value
set -o noglob # also local to the function
...
}


(function support was added to the Bourne shell later, but with a different syntax (f() command) and ksh added support for that one as well later; the Bourne shell never had local scope (except of course via subshells))



The local builtin AFAIK was added first to the Almquist shell (used in BSDs, dash, busybox sh) in 1989, but works significantly differently from ksh's typeset. ash derivatives don't support typeset as an alias to local, but you can always define one by hand.



bash and zsh added typeset aliased to local in 1989 and 1991 respectively.



pdksh and its derivatives added local as an alias to typeset in 1994. posh (based on pdksh) removed typeset (for strict compliance to the Debian Policy that requires local, but not typeset).



POSIX initially objected to specifying typeset on the ground that it was dynamic scoping. So ksh93 (a rewrite of ksh in 1993 by David Korn) switched to static scoping instead. Also in ksh93, as opposed to ksh88, local scoping is only done for functions declared with the ksh syntax (function f {...}), not the Bourne syntax (f() {...}).



ksh93 still doesn't have local.



yash (written much later), has typeset (a la ksh88), but not local.



@Schily maintains a Bourne shell descendant which has been recently made mostly POSIX compliant, called bosh that supports local scope since version 2016-07-06 (with local, similar to ash).



So the Bourne-like shells that have some form of local scope for variables today are:




  • ksh, all implementations and their derivatives (ksh88, ksh93, pdksh and derivatives like posh, mksh, OpenBSD sh).

  • ash and all its derivatives (NetBSD sh, FreeBSD sh, dash, busybox sh)

  • bash

  • zsh

  • yash

  • bosh


As far as the sh of different systems go, note that there are systems where the POSIX sh is in /bin (most), and others where it's not (like Solaris where it's in /usr/xpg4/bin). For the sh implementation on various systems we have:




  • ksh88: most SysV-derived commercial Unices (AIX, HP/UX, Solaris¹...)

  • bash: most GNU/Linux systems, Cygwin, macOS

  • ash: by default on Debian and most derivatives (including Ubuntu, Linux/Mint) though can be changed by the admin to bash or mksh. NetBSD, FreeBSD and some of their derivatives (not macOS).

  • busybox sh: many if not most embedded Linux systems

  • pdksh or derivatives: OpenBSD, MirOS


Now, where they differ:





  • typeset (ksh, pdksh, bash, zsh, yash) vs local (pdksh, bash, zsh, ash).

  • static (ksh93, in function f {...} function), vs dynamic scoping (all other shells). For instance, whether function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f outputs 1 or 2.

  • whether local/typeset just makes the variable local (ash, bosh), or creates a new instance of the variable (other shells). For instance, whether v=1; f() { local v; echo "${v:-empty}"; }; f outputs 1 or empty (see also the localvar_inherit option in bash 5.0 and above).

  • with those that create a new variable, whether the new one inherits the attributes (like export) and/or type and which ones from the variable in the parent scope. For instance, whether export V=1; f() { local V=2; printenv V; }; f prints 1, 2 or nothing.

  • whether that new variable has an initial value (empty, 0, empty list, depending on type, zsh) or is initially unset.

  • whether unset V on a variable in a local scope leaves the variable unset, or just peels one level of scoping (mksh, yash, bash under some circumstances). For instance, whether v=1; f() { local v=2; unset v; echo "$v"; } outputs 1 or nothing (see also the localvar_unset option in bash 5.0 and above).

  • whether you can declare local a variable that was readonly in the parent scope.

  • the interactions with v=value myfunction where myfunction itself declares v as local or not.

  • like for export, whether the arguments are parsed as normal command arguments or as assignments (and under what condition).


That's the ones I'm thinking of just now. Check the austin group bug above for more details.



As far as local scoping for shell options (as opposed to variables), shells supporting it are:





  • ksh88 (with both function definition syntax): done by default, I'm not aware of any way to disable it.


  • ash (since 1989): with local -. It makes the $- parameter (which stores the list of options) local.


  • ksh93: now only done for function f {...} functions.


  • zsh (since 1995). With setopt localoptions. Also with emulate -L for the emulation mode (and its set of options) to be made local to the function.


  • bash (since 2016) with local - like in ash.




¹ the POSIX sh on Solaris is /usr/xpg4/bin/sh (though it has many conformance bugs including those options local to functions). /bin/sh up to Solaris 10 was the Bourne shell (so no local scope), and since Solaris 11 is ksh93






share|improve this answer


























  • Bourne (heirloom version) supports functions as f() { list; }.

    – Isaac
    Jan 11 at 12:25






  • 1





    @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

    – Stéphane Chazelas
    Jan 11 at 14:13











  • @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

    – Stéphane Chazelas
    Jan 11 at 14:20











  • See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

    – Stéphane Chazelas
    Jan 11 at 14:26



















1














To follow up on a hint in Stéphane's answer, using subshells gets you the local effect. I don't have access to a true POSIX shell, but this works in busybox ash -- declare your functions with () parentheses instead of {} braces. That forces the function to run in a subshell.



func() (
echo "in func, before declaring: x=$x"
x=10
echo "in func, after declaring: x=$x"
)

x=5
echo "before func: x=$x"
func
echo "after func: x=$x"


outputs



before func: x=5
in func, before declaring: x=5
in func, after declaring: x=10
after func: x=5


That shows that the function has access to global variables, and setting variables in the function does not alter the globals. This is a technique I sometimes use when I want to alter $IFS or cd to a different directory, but I don't want those actions to affect the rest of the program.






share|improve this answer

























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "106"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f493729%2flist-of-shells-that-support-local-keyword-for-defining-local-variables%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    It's not as simple as supporting local or not. There is a lot of variation on the syntax and how it's done between shells that have one form or other of local scope.



    That's why it's very hard to come up with a standard that agrees with all. See http://austingroupbugs.net/bug_view_page.php?bug_id=767 for the POSIX effort on that front.



    local scope was added first in ksh in the early 80s.



    The syntax to declare a local variable in a function was with typeset:



    function f {
    typeset var=value
    set -o noglob # also local to the function
    ...
    }


    (function support was added to the Bourne shell later, but with a different syntax (f() command) and ksh added support for that one as well later; the Bourne shell never had local scope (except of course via subshells))



    The local builtin AFAIK was added first to the Almquist shell (used in BSDs, dash, busybox sh) in 1989, but works significantly differently from ksh's typeset. ash derivatives don't support typeset as an alias to local, but you can always define one by hand.



    bash and zsh added typeset aliased to local in 1989 and 1991 respectively.



    pdksh and its derivatives added local as an alias to typeset in 1994. posh (based on pdksh) removed typeset (for strict compliance to the Debian Policy that requires local, but not typeset).



    POSIX initially objected to specifying typeset on the ground that it was dynamic scoping. So ksh93 (a rewrite of ksh in 1993 by David Korn) switched to static scoping instead. Also in ksh93, as opposed to ksh88, local scoping is only done for functions declared with the ksh syntax (function f {...}), not the Bourne syntax (f() {...}).



    ksh93 still doesn't have local.



    yash (written much later), has typeset (a la ksh88), but not local.



    @Schily maintains a Bourne shell descendant which has been recently made mostly POSIX compliant, called bosh that supports local scope since version 2016-07-06 (with local, similar to ash).



    So the Bourne-like shells that have some form of local scope for variables today are:




    • ksh, all implementations and their derivatives (ksh88, ksh93, pdksh and derivatives like posh, mksh, OpenBSD sh).

    • ash and all its derivatives (NetBSD sh, FreeBSD sh, dash, busybox sh)

    • bash

    • zsh

    • yash

    • bosh


    As far as the sh of different systems go, note that there are systems where the POSIX sh is in /bin (most), and others where it's not (like Solaris where it's in /usr/xpg4/bin). For the sh implementation on various systems we have:




    • ksh88: most SysV-derived commercial Unices (AIX, HP/UX, Solaris¹...)

    • bash: most GNU/Linux systems, Cygwin, macOS

    • ash: by default on Debian and most derivatives (including Ubuntu, Linux/Mint) though can be changed by the admin to bash or mksh. NetBSD, FreeBSD and some of their derivatives (not macOS).

    • busybox sh: many if not most embedded Linux systems

    • pdksh or derivatives: OpenBSD, MirOS


    Now, where they differ:





    • typeset (ksh, pdksh, bash, zsh, yash) vs local (pdksh, bash, zsh, ash).

    • static (ksh93, in function f {...} function), vs dynamic scoping (all other shells). For instance, whether function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f outputs 1 or 2.

    • whether local/typeset just makes the variable local (ash, bosh), or creates a new instance of the variable (other shells). For instance, whether v=1; f() { local v; echo "${v:-empty}"; }; f outputs 1 or empty (see also the localvar_inherit option in bash 5.0 and above).

    • with those that create a new variable, whether the new one inherits the attributes (like export) and/or type and which ones from the variable in the parent scope. For instance, whether export V=1; f() { local V=2; printenv V; }; f prints 1, 2 or nothing.

    • whether that new variable has an initial value (empty, 0, empty list, depending on type, zsh) or is initially unset.

    • whether unset V on a variable in a local scope leaves the variable unset, or just peels one level of scoping (mksh, yash, bash under some circumstances). For instance, whether v=1; f() { local v=2; unset v; echo "$v"; } outputs 1 or nothing (see also the localvar_unset option in bash 5.0 and above).

    • whether you can declare local a variable that was readonly in the parent scope.

    • the interactions with v=value myfunction where myfunction itself declares v as local or not.

    • like for export, whether the arguments are parsed as normal command arguments or as assignments (and under what condition).


    That's the ones I'm thinking of just now. Check the austin group bug above for more details.



    As far as local scoping for shell options (as opposed to variables), shells supporting it are:





    • ksh88 (with both function definition syntax): done by default, I'm not aware of any way to disable it.


    • ash (since 1989): with local -. It makes the $- parameter (which stores the list of options) local.


    • ksh93: now only done for function f {...} functions.


    • zsh (since 1995). With setopt localoptions. Also with emulate -L for the emulation mode (and its set of options) to be made local to the function.


    • bash (since 2016) with local - like in ash.




    ¹ the POSIX sh on Solaris is /usr/xpg4/bin/sh (though it has many conformance bugs including those options local to functions). /bin/sh up to Solaris 10 was the Bourne shell (so no local scope), and since Solaris 11 is ksh93






    share|improve this answer


























    • Bourne (heirloom version) supports functions as f() { list; }.

      – Isaac
      Jan 11 at 12:25






    • 1





      @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

      – Stéphane Chazelas
      Jan 11 at 14:13











    • @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

      – Stéphane Chazelas
      Jan 11 at 14:20











    • See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

      – Stéphane Chazelas
      Jan 11 at 14:26
















    7














    It's not as simple as supporting local or not. There is a lot of variation on the syntax and how it's done between shells that have one form or other of local scope.



    That's why it's very hard to come up with a standard that agrees with all. See http://austingroupbugs.net/bug_view_page.php?bug_id=767 for the POSIX effort on that front.



    local scope was added first in ksh in the early 80s.



    The syntax to declare a local variable in a function was with typeset:



    function f {
    typeset var=value
    set -o noglob # also local to the function
    ...
    }


    (function support was added to the Bourne shell later, but with a different syntax (f() command) and ksh added support for that one as well later; the Bourne shell never had local scope (except of course via subshells))



    The local builtin AFAIK was added first to the Almquist shell (used in BSDs, dash, busybox sh) in 1989, but works significantly differently from ksh's typeset. ash derivatives don't support typeset as an alias to local, but you can always define one by hand.



    bash and zsh added typeset aliased to local in 1989 and 1991 respectively.



    pdksh and its derivatives added local as an alias to typeset in 1994. posh (based on pdksh) removed typeset (for strict compliance to the Debian Policy that requires local, but not typeset).



    POSIX initially objected to specifying typeset on the ground that it was dynamic scoping. So ksh93 (a rewrite of ksh in 1993 by David Korn) switched to static scoping instead. Also in ksh93, as opposed to ksh88, local scoping is only done for functions declared with the ksh syntax (function f {...}), not the Bourne syntax (f() {...}).



    ksh93 still doesn't have local.



    yash (written much later), has typeset (a la ksh88), but not local.



    @Schily maintains a Bourne shell descendant which has been recently made mostly POSIX compliant, called bosh that supports local scope since version 2016-07-06 (with local, similar to ash).



    So the Bourne-like shells that have some form of local scope for variables today are:




    • ksh, all implementations and their derivatives (ksh88, ksh93, pdksh and derivatives like posh, mksh, OpenBSD sh).

    • ash and all its derivatives (NetBSD sh, FreeBSD sh, dash, busybox sh)

    • bash

    • zsh

    • yash

    • bosh


    As far as the sh of different systems go, note that there are systems where the POSIX sh is in /bin (most), and others where it's not (like Solaris where it's in /usr/xpg4/bin). For the sh implementation on various systems we have:




    • ksh88: most SysV-derived commercial Unices (AIX, HP/UX, Solaris¹...)

    • bash: most GNU/Linux systems, Cygwin, macOS

    • ash: by default on Debian and most derivatives (including Ubuntu, Linux/Mint) though can be changed by the admin to bash or mksh. NetBSD, FreeBSD and some of their derivatives (not macOS).

    • busybox sh: many if not most embedded Linux systems

    • pdksh or derivatives: OpenBSD, MirOS


    Now, where they differ:





    • typeset (ksh, pdksh, bash, zsh, yash) vs local (pdksh, bash, zsh, ash).

    • static (ksh93, in function f {...} function), vs dynamic scoping (all other shells). For instance, whether function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f outputs 1 or 2.

    • whether local/typeset just makes the variable local (ash, bosh), or creates a new instance of the variable (other shells). For instance, whether v=1; f() { local v; echo "${v:-empty}"; }; f outputs 1 or empty (see also the localvar_inherit option in bash 5.0 and above).

    • with those that create a new variable, whether the new one inherits the attributes (like export) and/or type and which ones from the variable in the parent scope. For instance, whether export V=1; f() { local V=2; printenv V; }; f prints 1, 2 or nothing.

    • whether that new variable has an initial value (empty, 0, empty list, depending on type, zsh) or is initially unset.

    • whether unset V on a variable in a local scope leaves the variable unset, or just peels one level of scoping (mksh, yash, bash under some circumstances). For instance, whether v=1; f() { local v=2; unset v; echo "$v"; } outputs 1 or nothing (see also the localvar_unset option in bash 5.0 and above).

    • whether you can declare local a variable that was readonly in the parent scope.

    • the interactions with v=value myfunction where myfunction itself declares v as local or not.

    • like for export, whether the arguments are parsed as normal command arguments or as assignments (and under what condition).


    That's the ones I'm thinking of just now. Check the austin group bug above for more details.



    As far as local scoping for shell options (as opposed to variables), shells supporting it are:





    • ksh88 (with both function definition syntax): done by default, I'm not aware of any way to disable it.


    • ash (since 1989): with local -. It makes the $- parameter (which stores the list of options) local.


    • ksh93: now only done for function f {...} functions.


    • zsh (since 1995). With setopt localoptions. Also with emulate -L for the emulation mode (and its set of options) to be made local to the function.


    • bash (since 2016) with local - like in ash.




    ¹ the POSIX sh on Solaris is /usr/xpg4/bin/sh (though it has many conformance bugs including those options local to functions). /bin/sh up to Solaris 10 was the Bourne shell (so no local scope), and since Solaris 11 is ksh93






    share|improve this answer


























    • Bourne (heirloom version) supports functions as f() { list; }.

      – Isaac
      Jan 11 at 12:25






    • 1





      @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

      – Stéphane Chazelas
      Jan 11 at 14:13











    • @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

      – Stéphane Chazelas
      Jan 11 at 14:20











    • See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

      – Stéphane Chazelas
      Jan 11 at 14:26














    7












    7








    7







    It's not as simple as supporting local or not. There is a lot of variation on the syntax and how it's done between shells that have one form or other of local scope.



    That's why it's very hard to come up with a standard that agrees with all. See http://austingroupbugs.net/bug_view_page.php?bug_id=767 for the POSIX effort on that front.



    local scope was added first in ksh in the early 80s.



    The syntax to declare a local variable in a function was with typeset:



    function f {
    typeset var=value
    set -o noglob # also local to the function
    ...
    }


    (function support was added to the Bourne shell later, but with a different syntax (f() command) and ksh added support for that one as well later; the Bourne shell never had local scope (except of course via subshells))



    The local builtin AFAIK was added first to the Almquist shell (used in BSDs, dash, busybox sh) in 1989, but works significantly differently from ksh's typeset. ash derivatives don't support typeset as an alias to local, but you can always define one by hand.



    bash and zsh added typeset aliased to local in 1989 and 1991 respectively.



    pdksh and its derivatives added local as an alias to typeset in 1994. posh (based on pdksh) removed typeset (for strict compliance to the Debian Policy that requires local, but not typeset).



    POSIX initially objected to specifying typeset on the ground that it was dynamic scoping. So ksh93 (a rewrite of ksh in 1993 by David Korn) switched to static scoping instead. Also in ksh93, as opposed to ksh88, local scoping is only done for functions declared with the ksh syntax (function f {...}), not the Bourne syntax (f() {...}).



    ksh93 still doesn't have local.



    yash (written much later), has typeset (a la ksh88), but not local.



    @Schily maintains a Bourne shell descendant which has been recently made mostly POSIX compliant, called bosh that supports local scope since version 2016-07-06 (with local, similar to ash).



    So the Bourne-like shells that have some form of local scope for variables today are:




    • ksh, all implementations and their derivatives (ksh88, ksh93, pdksh and derivatives like posh, mksh, OpenBSD sh).

    • ash and all its derivatives (NetBSD sh, FreeBSD sh, dash, busybox sh)

    • bash

    • zsh

    • yash

    • bosh


    As far as the sh of different systems go, note that there are systems where the POSIX sh is in /bin (most), and others where it's not (like Solaris where it's in /usr/xpg4/bin). For the sh implementation on various systems we have:




    • ksh88: most SysV-derived commercial Unices (AIX, HP/UX, Solaris¹...)

    • bash: most GNU/Linux systems, Cygwin, macOS

    • ash: by default on Debian and most derivatives (including Ubuntu, Linux/Mint) though can be changed by the admin to bash or mksh. NetBSD, FreeBSD and some of their derivatives (not macOS).

    • busybox sh: many if not most embedded Linux systems

    • pdksh or derivatives: OpenBSD, MirOS


    Now, where they differ:





    • typeset (ksh, pdksh, bash, zsh, yash) vs local (pdksh, bash, zsh, ash).

    • static (ksh93, in function f {...} function), vs dynamic scoping (all other shells). For instance, whether function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f outputs 1 or 2.

    • whether local/typeset just makes the variable local (ash, bosh), or creates a new instance of the variable (other shells). For instance, whether v=1; f() { local v; echo "${v:-empty}"; }; f outputs 1 or empty (see also the localvar_inherit option in bash 5.0 and above).

    • with those that create a new variable, whether the new one inherits the attributes (like export) and/or type and which ones from the variable in the parent scope. For instance, whether export V=1; f() { local V=2; printenv V; }; f prints 1, 2 or nothing.

    • whether that new variable has an initial value (empty, 0, empty list, depending on type, zsh) or is initially unset.

    • whether unset V on a variable in a local scope leaves the variable unset, or just peels one level of scoping (mksh, yash, bash under some circumstances). For instance, whether v=1; f() { local v=2; unset v; echo "$v"; } outputs 1 or nothing (see also the localvar_unset option in bash 5.0 and above).

    • whether you can declare local a variable that was readonly in the parent scope.

    • the interactions with v=value myfunction where myfunction itself declares v as local or not.

    • like for export, whether the arguments are parsed as normal command arguments or as assignments (and under what condition).


    That's the ones I'm thinking of just now. Check the austin group bug above for more details.



    As far as local scoping for shell options (as opposed to variables), shells supporting it are:





    • ksh88 (with both function definition syntax): done by default, I'm not aware of any way to disable it.


    • ash (since 1989): with local -. It makes the $- parameter (which stores the list of options) local.


    • ksh93: now only done for function f {...} functions.


    • zsh (since 1995). With setopt localoptions. Also with emulate -L for the emulation mode (and its set of options) to be made local to the function.


    • bash (since 2016) with local - like in ash.




    ¹ the POSIX sh on Solaris is /usr/xpg4/bin/sh (though it has many conformance bugs including those options local to functions). /bin/sh up to Solaris 10 was the Bourne shell (so no local scope), and since Solaris 11 is ksh93






    share|improve this answer















    It's not as simple as supporting local or not. There is a lot of variation on the syntax and how it's done between shells that have one form or other of local scope.



    That's why it's very hard to come up with a standard that agrees with all. See http://austingroupbugs.net/bug_view_page.php?bug_id=767 for the POSIX effort on that front.



    local scope was added first in ksh in the early 80s.



    The syntax to declare a local variable in a function was with typeset:



    function f {
    typeset var=value
    set -o noglob # also local to the function
    ...
    }


    (function support was added to the Bourne shell later, but with a different syntax (f() command) and ksh added support for that one as well later; the Bourne shell never had local scope (except of course via subshells))



    The local builtin AFAIK was added first to the Almquist shell (used in BSDs, dash, busybox sh) in 1989, but works significantly differently from ksh's typeset. ash derivatives don't support typeset as an alias to local, but you can always define one by hand.



    bash and zsh added typeset aliased to local in 1989 and 1991 respectively.



    pdksh and its derivatives added local as an alias to typeset in 1994. posh (based on pdksh) removed typeset (for strict compliance to the Debian Policy that requires local, but not typeset).



    POSIX initially objected to specifying typeset on the ground that it was dynamic scoping. So ksh93 (a rewrite of ksh in 1993 by David Korn) switched to static scoping instead. Also in ksh93, as opposed to ksh88, local scoping is only done for functions declared with the ksh syntax (function f {...}), not the Bourne syntax (f() {...}).



    ksh93 still doesn't have local.



    yash (written much later), has typeset (a la ksh88), but not local.



    @Schily maintains a Bourne shell descendant which has been recently made mostly POSIX compliant, called bosh that supports local scope since version 2016-07-06 (with local, similar to ash).



    So the Bourne-like shells that have some form of local scope for variables today are:




    • ksh, all implementations and their derivatives (ksh88, ksh93, pdksh and derivatives like posh, mksh, OpenBSD sh).

    • ash and all its derivatives (NetBSD sh, FreeBSD sh, dash, busybox sh)

    • bash

    • zsh

    • yash

    • bosh


    As far as the sh of different systems go, note that there are systems where the POSIX sh is in /bin (most), and others where it's not (like Solaris where it's in /usr/xpg4/bin). For the sh implementation on various systems we have:




    • ksh88: most SysV-derived commercial Unices (AIX, HP/UX, Solaris¹...)

    • bash: most GNU/Linux systems, Cygwin, macOS

    • ash: by default on Debian and most derivatives (including Ubuntu, Linux/Mint) though can be changed by the admin to bash or mksh. NetBSD, FreeBSD and some of their derivatives (not macOS).

    • busybox sh: many if not most embedded Linux systems

    • pdksh or derivatives: OpenBSD, MirOS


    Now, where they differ:





    • typeset (ksh, pdksh, bash, zsh, yash) vs local (pdksh, bash, zsh, ash).

    • static (ksh93, in function f {...} function), vs dynamic scoping (all other shells). For instance, whether function f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f outputs 1 or 2.

    • whether local/typeset just makes the variable local (ash, bosh), or creates a new instance of the variable (other shells). For instance, whether v=1; f() { local v; echo "${v:-empty}"; }; f outputs 1 or empty (see also the localvar_inherit option in bash 5.0 and above).

    • with those that create a new variable, whether the new one inherits the attributes (like export) and/or type and which ones from the variable in the parent scope. For instance, whether export V=1; f() { local V=2; printenv V; }; f prints 1, 2 or nothing.

    • whether that new variable has an initial value (empty, 0, empty list, depending on type, zsh) or is initially unset.

    • whether unset V on a variable in a local scope leaves the variable unset, or just peels one level of scoping (mksh, yash, bash under some circumstances). For instance, whether v=1; f() { local v=2; unset v; echo "$v"; } outputs 1 or nothing (see also the localvar_unset option in bash 5.0 and above).

    • whether you can declare local a variable that was readonly in the parent scope.

    • the interactions with v=value myfunction where myfunction itself declares v as local or not.

    • like for export, whether the arguments are parsed as normal command arguments or as assignments (and under what condition).


    That's the ones I'm thinking of just now. Check the austin group bug above for more details.



    As far as local scoping for shell options (as opposed to variables), shells supporting it are:





    • ksh88 (with both function definition syntax): done by default, I'm not aware of any way to disable it.


    • ash (since 1989): with local -. It makes the $- parameter (which stores the list of options) local.


    • ksh93: now only done for function f {...} functions.


    • zsh (since 1995). With setopt localoptions. Also with emulate -L for the emulation mode (and its set of options) to be made local to the function.


    • bash (since 2016) with local - like in ash.




    ¹ the POSIX sh on Solaris is /usr/xpg4/bin/sh (though it has many conformance bugs including those options local to functions). /bin/sh up to Solaris 10 was the Bourne shell (so no local scope), and since Solaris 11 is ksh93







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 3 mins ago

























    answered Jan 10 at 15:29









    Stéphane ChazelasStéphane Chazelas

    303k56570924




    303k56570924













    • Bourne (heirloom version) supports functions as f() { list; }.

      – Isaac
      Jan 11 at 12:25






    • 1





      @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

      – Stéphane Chazelas
      Jan 11 at 14:13











    • @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

      – Stéphane Chazelas
      Jan 11 at 14:20











    • See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

      – Stéphane Chazelas
      Jan 11 at 14:26



















    • Bourne (heirloom version) supports functions as f() { list; }.

      – Isaac
      Jan 11 at 12:25






    • 1





      @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

      – Stéphane Chazelas
      Jan 11 at 14:13











    • @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

      – Stéphane Chazelas
      Jan 11 at 14:20











    • See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

      – Stéphane Chazelas
      Jan 11 at 14:26

















    Bourne (heirloom version) supports functions as f() { list; }.

    – Isaac
    Jan 11 at 12:25





    Bourne (heirloom version) supports functions as f() { list; }.

    – Isaac
    Jan 11 at 12:25




    1




    1





    @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

    – Stéphane Chazelas
    Jan 11 at 14:13





    @Isaac, it's f() any-command (except that if any-command is a simple command, it can't have redirections). The POSIX syntax is f() any-compound-command. {...} is both a command and compound command. The Bourne shell initially didn't have functions. Function support was added in SVR2 in 1984 with a different syntax from that of ksh (1983) which is what I'm saying here.

    – Stéphane Chazelas
    Jan 11 at 14:13













    @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

    – Stéphane Chazelas
    Jan 11 at 14:20





    @Isaac, the best source of information about the Bourne shell is at in-ulm.de/~mascheck/bourne/index.html

    – Stéphane Chazelas
    Jan 11 at 14:20













    See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

    – Stéphane Chazelas
    Jan 11 at 14:26





    See also web.archive.org/web/20000816225337if_/http://… where David Korn mentioned that support for functions in the Bourne shell was added in 1982 (1984 was when SVR2 was released) and the ksh function f { ....} predated that (ksh first announced in 1983 AFAIK).

    – Stéphane Chazelas
    Jan 11 at 14:26













    1














    To follow up on a hint in Stéphane's answer, using subshells gets you the local effect. I don't have access to a true POSIX shell, but this works in busybox ash -- declare your functions with () parentheses instead of {} braces. That forces the function to run in a subshell.



    func() (
    echo "in func, before declaring: x=$x"
    x=10
    echo "in func, after declaring: x=$x"
    )

    x=5
    echo "before func: x=$x"
    func
    echo "after func: x=$x"


    outputs



    before func: x=5
    in func, before declaring: x=5
    in func, after declaring: x=10
    after func: x=5


    That shows that the function has access to global variables, and setting variables in the function does not alter the globals. This is a technique I sometimes use when I want to alter $IFS or cd to a different directory, but I don't want those actions to affect the rest of the program.






    share|improve this answer






























      1














      To follow up on a hint in Stéphane's answer, using subshells gets you the local effect. I don't have access to a true POSIX shell, but this works in busybox ash -- declare your functions with () parentheses instead of {} braces. That forces the function to run in a subshell.



      func() (
      echo "in func, before declaring: x=$x"
      x=10
      echo "in func, after declaring: x=$x"
      )

      x=5
      echo "before func: x=$x"
      func
      echo "after func: x=$x"


      outputs



      before func: x=5
      in func, before declaring: x=5
      in func, after declaring: x=10
      after func: x=5


      That shows that the function has access to global variables, and setting variables in the function does not alter the globals. This is a technique I sometimes use when I want to alter $IFS or cd to a different directory, but I don't want those actions to affect the rest of the program.






      share|improve this answer




























        1












        1








        1







        To follow up on a hint in Stéphane's answer, using subshells gets you the local effect. I don't have access to a true POSIX shell, but this works in busybox ash -- declare your functions with () parentheses instead of {} braces. That forces the function to run in a subshell.



        func() (
        echo "in func, before declaring: x=$x"
        x=10
        echo "in func, after declaring: x=$x"
        )

        x=5
        echo "before func: x=$x"
        func
        echo "after func: x=$x"


        outputs



        before func: x=5
        in func, before declaring: x=5
        in func, after declaring: x=10
        after func: x=5


        That shows that the function has access to global variables, and setting variables in the function does not alter the globals. This is a technique I sometimes use when I want to alter $IFS or cd to a different directory, but I don't want those actions to affect the rest of the program.






        share|improve this answer















        To follow up on a hint in Stéphane's answer, using subshells gets you the local effect. I don't have access to a true POSIX shell, but this works in busybox ash -- declare your functions with () parentheses instead of {} braces. That forces the function to run in a subshell.



        func() (
        echo "in func, before declaring: x=$x"
        x=10
        echo "in func, after declaring: x=$x"
        )

        x=5
        echo "before func: x=$x"
        func
        echo "after func: x=$x"


        outputs



        before func: x=5
        in func, before declaring: x=5
        in func, after declaring: x=10
        after func: x=5


        That shows that the function has access to global variables, and setting variables in the function does not alter the globals. This is a technique I sometimes use when I want to alter $IFS or cd to a different directory, but I don't want those actions to affect the rest of the program.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        answered Jan 11 at 0:05


























        community wiki





        glenn jackman































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f493729%2flist-of-shells-that-support-local-keyword-for-defining-local-variables%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            濃尾地震

            How to rewrite equation of hyperbola in standard form

            No ethernet ip address in my vocore2