List of shells that support `local` keyword for defining local variablestypeset in ksh93 not working as...
What is the origin of the term describing a game as a ‘Heartbreaker’?
Are there any instances of members of different Hogwarts houses coupling up and marrying each other?
Determining if file in projected or geographic coordinates using ArcGIS Desktop?
What are the advantages and disadvantages of Preprints.org compared with arXiv?
Why was "leaping into the river" a valid trial outcome to prove one's innocence?
"Not enough RAM " error in PIC16F877a
How should we understand "unobscured by flying friends" in this context?
A medieval fantasy adventurer lights a torch in a 100% pure oxygen room. What happens?
Is there a basic list of ways in which a low-level Rogue can get advantage for sneak attack?
Is English tonal for some words, like "permit"?
What is the use of FullForm in Mathematica?
Should my game's entities use global variables?
Job offer without any details but asking me to withdraw other applications - is it normal?
What is going on: C++ std::move on std::shared_ptr increases use_count?
Calculate time difference between two dates
Creating a Master Image to roll out to 30 new Machines Licensing Issues
What's the biggest difference between these two photos?
What is negative current?
Is the space of Radon measures a Polish space or at least separable?
What does my colleagues' question really mean?
Writing a love interest for my hero
Can a level 1 Fiend Pact warlock cast a scroll of fireball?
Can I use ratchet straps to lift a dolly into a truck bed?
Are there any space probes or landers which regained communication after being lost?
List of shells that support `local` keyword for defining local variables
typeset in ksh93 not working as expectedDo shells support recursion?Can we configure different shells for different users on a single Linux/Unix distribution?What does it mean to be “sh compatible”?Which shells have functions where “local” does not alter exported variables for child processes?Scope of Local Variables in Shell Functionszsh fail to keep unquoted `$*` and `$@` equalShells initialization filesDo shells other than Bash and Zsh support ANSI-C quoting? e.g. $'string'Can we write a script to run some command within each interactive bash shell process?Konsole does not run shell specified in /etc/passwd
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
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
|
show 9 more comments
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
1
dash supports them, ksh supports them but I think you need to usetypeset
instead oflocal
– Jesse_b
Jan 10 at 14:18
6
@Jesse_b ksh doesn't support thelocal
keyword; it does support local variables, but viatypeset
not via thelocal
, and only in funcs defined asfunction foo { }
, not in funcs defined asfoo(){ }
.
– 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 abouttypeset
not working in functions defined asfoo(){ ... }
? 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
|
show 9 more comments
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
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
shell-script shell
edited Jan 28 at 6:41
Stéphane Chazelas
333k58 gold badges652 silver badges1022 bronze badges
333k58 gold badges652 silver badges1022 bronze badges
asked Jan 10 at 14:13
mjamja
4075 silver badges16 bronze badges
4075 silver badges16 bronze badges
1
dash supports them, ksh supports them but I think you need to usetypeset
instead oflocal
– Jesse_b
Jan 10 at 14:18
6
@Jesse_b ksh doesn't support thelocal
keyword; it does support local variables, but viatypeset
not via thelocal
, and only in funcs defined asfunction foo { }
, not in funcs defined asfoo(){ }
.
– 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 abouttypeset
not working in functions defined asfoo(){ ... }
? 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
|
show 9 more comments
1
dash supports them, ksh supports them but I think you need to usetypeset
instead oflocal
– Jesse_b
Jan 10 at 14:18
6
@Jesse_b ksh doesn't support thelocal
keyword; it does support local variables, but viatypeset
not via thelocal
, and only in funcs defined asfunction foo { }
, not in funcs defined asfoo(){ }
.
– 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 abouttypeset
not working in functions defined asfoo(){ ... }
? 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
6
6
@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
|
show 9 more comments
2 Answers
2
active
oldest
votes
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.
ksh88 added local
as an undocumented alias to typeset
circa 1990 and pdksh and its derivatives 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() {...}
) and the local
alias was removed.
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) vslocal
(ksh88, pdksh, bash, zsh, ash).- static (ksh93, in
function f {...}
function), vs dynamic scoping (all other shells). For instance, whetherfunction f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
outputs1
or2
. - whether
local
/typeset
just makes the variable local (ash
,bosh
), or creates a new instance of the variable (other shells). For instance, whetherv=1; f() { local v; echo "${v:-empty}"; }; f
outputs1
orempty
(see also thelocalvar_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, whetherexport V=1; f() { local V=2; printenv V; }; f
prints1
,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 variableunset
, or just peels one level of scoping (mksh
,yash
,bash
under some circumstances). For instance, whetherv=1; f() { local v=2; unset v; echo "$v"; }
outputs1
or nothing (see also thelocalvar_unset
option in bash 5.0 and above): whether it's a keyword or only mere builtin and under what condition it's considered as a keyword. - whether you can declare local a variable that was readonly in the parent scope.
- the interactions with
v=value myfunction
wheremyfunction
itself declaresv
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): withlocal -
. It makes the$-
parameter (which stores the list of options) local.
ksh93
: now only done forfunction f {...}
functions.
zsh
(since 1995). Withsetopt localoptions
. Also withemulate -L
for the emulation mode (and its set of options) to be made local to the function.
bash
(since 2016) withlocal -
like inash
.
¹ 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
Bourne (heirloom version) supports functions asf() { list; }
.
– Isaac
Jan 11 at 12:25
1
@Isaac, it'sf() any-command
(except that ifany-command
is a simple command, it can't have redirections). The POSIX syntax isf() 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 kshfunction f { ....}
predated that (ksh first announced in 1983 AFAIK).
– Stéphane Chazelas
Jan 11 at 14:26
add a comment |
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.
add a comment |
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/4.0/"u003ecc by-sa 4.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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
ksh88 added local
as an undocumented alias to typeset
circa 1990 and pdksh and its derivatives 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() {...}
) and the local
alias was removed.
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) vslocal
(ksh88, pdksh, bash, zsh, ash).- static (ksh93, in
function f {...}
function), vs dynamic scoping (all other shells). For instance, whetherfunction f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
outputs1
or2
. - whether
local
/typeset
just makes the variable local (ash
,bosh
), or creates a new instance of the variable (other shells). For instance, whetherv=1; f() { local v; echo "${v:-empty}"; }; f
outputs1
orempty
(see also thelocalvar_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, whetherexport V=1; f() { local V=2; printenv V; }; f
prints1
,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 variableunset
, or just peels one level of scoping (mksh
,yash
,bash
under some circumstances). For instance, whetherv=1; f() { local v=2; unset v; echo "$v"; }
outputs1
or nothing (see also thelocalvar_unset
option in bash 5.0 and above): whether it's a keyword or only mere builtin and under what condition it's considered as a keyword. - whether you can declare local a variable that was readonly in the parent scope.
- the interactions with
v=value myfunction
wheremyfunction
itself declaresv
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): withlocal -
. It makes the$-
parameter (which stores the list of options) local.
ksh93
: now only done forfunction f {...}
functions.
zsh
(since 1995). Withsetopt localoptions
. Also withemulate -L
for the emulation mode (and its set of options) to be made local to the function.
bash
(since 2016) withlocal -
like inash
.
¹ 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
Bourne (heirloom version) supports functions asf() { list; }
.
– Isaac
Jan 11 at 12:25
1
@Isaac, it'sf() any-command
(except that ifany-command
is a simple command, it can't have redirections). The POSIX syntax isf() 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 kshfunction f { ....}
predated that (ksh first announced in 1983 AFAIK).
– Stéphane Chazelas
Jan 11 at 14:26
add a comment |
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.
ksh88 added local
as an undocumented alias to typeset
circa 1990 and pdksh and its derivatives 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() {...}
) and the local
alias was removed.
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) vslocal
(ksh88, pdksh, bash, zsh, ash).- static (ksh93, in
function f {...}
function), vs dynamic scoping (all other shells). For instance, whetherfunction f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
outputs1
or2
. - whether
local
/typeset
just makes the variable local (ash
,bosh
), or creates a new instance of the variable (other shells). For instance, whetherv=1; f() { local v; echo "${v:-empty}"; }; f
outputs1
orempty
(see also thelocalvar_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, whetherexport V=1; f() { local V=2; printenv V; }; f
prints1
,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 variableunset
, or just peels one level of scoping (mksh
,yash
,bash
under some circumstances). For instance, whetherv=1; f() { local v=2; unset v; echo "$v"; }
outputs1
or nothing (see also thelocalvar_unset
option in bash 5.0 and above): whether it's a keyword or only mere builtin and under what condition it's considered as a keyword. - whether you can declare local a variable that was readonly in the parent scope.
- the interactions with
v=value myfunction
wheremyfunction
itself declaresv
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): withlocal -
. It makes the$-
parameter (which stores the list of options) local.
ksh93
: now only done forfunction f {...}
functions.
zsh
(since 1995). Withsetopt localoptions
. Also withemulate -L
for the emulation mode (and its set of options) to be made local to the function.
bash
(since 2016) withlocal -
like inash
.
¹ 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
Bourne (heirloom version) supports functions asf() { list; }
.
– Isaac
Jan 11 at 12:25
1
@Isaac, it'sf() any-command
(except that ifany-command
is a simple command, it can't have redirections). The POSIX syntax isf() 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 kshfunction f { ....}
predated that (ksh first announced in 1983 AFAIK).
– Stéphane Chazelas
Jan 11 at 14:26
add a comment |
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.
ksh88 added local
as an undocumented alias to typeset
circa 1990 and pdksh and its derivatives 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() {...}
) and the local
alias was removed.
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) vslocal
(ksh88, pdksh, bash, zsh, ash).- static (ksh93, in
function f {...}
function), vs dynamic scoping (all other shells). For instance, whetherfunction f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
outputs1
or2
. - whether
local
/typeset
just makes the variable local (ash
,bosh
), or creates a new instance of the variable (other shells). For instance, whetherv=1; f() { local v; echo "${v:-empty}"; }; f
outputs1
orempty
(see also thelocalvar_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, whetherexport V=1; f() { local V=2; printenv V; }; f
prints1
,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 variableunset
, or just peels one level of scoping (mksh
,yash
,bash
under some circumstances). For instance, whetherv=1; f() { local v=2; unset v; echo "$v"; }
outputs1
or nothing (see also thelocalvar_unset
option in bash 5.0 and above): whether it's a keyword or only mere builtin and under what condition it's considered as a keyword. - whether you can declare local a variable that was readonly in the parent scope.
- the interactions with
v=value myfunction
wheremyfunction
itself declaresv
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): withlocal -
. It makes the$-
parameter (which stores the list of options) local.
ksh93
: now only done forfunction f {...}
functions.
zsh
(since 1995). Withsetopt localoptions
. Also withemulate -L
for the emulation mode (and its set of options) to be made local to the function.
bash
(since 2016) withlocal -
like inash
.
¹ 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
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.
ksh88 added local
as an undocumented alias to typeset
circa 1990 and pdksh and its derivatives 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() {...}
) and the local
alias was removed.
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) vslocal
(ksh88, pdksh, bash, zsh, ash).- static (ksh93, in
function f {...}
function), vs dynamic scoping (all other shells). For instance, whetherfunction f { typeset v=1; g; echo "$v"; }; function g { v=2; }; f
outputs1
or2
. - whether
local
/typeset
just makes the variable local (ash
,bosh
), or creates a new instance of the variable (other shells). For instance, whetherv=1; f() { local v; echo "${v:-empty}"; }; f
outputs1
orempty
(see also thelocalvar_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, whetherexport V=1; f() { local V=2; printenv V; }; f
prints1
,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 variableunset
, or just peels one level of scoping (mksh
,yash
,bash
under some circumstances). For instance, whetherv=1; f() { local v=2; unset v; echo "$v"; }
outputs1
or nothing (see also thelocalvar_unset
option in bash 5.0 and above): whether it's a keyword or only mere builtin and under what condition it's considered as a keyword. - whether you can declare local a variable that was readonly in the parent scope.
- the interactions with
v=value myfunction
wheremyfunction
itself declaresv
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): withlocal -
. It makes the$-
parameter (which stores the list of options) local.
ksh93
: now only done forfunction f {...}
functions.
zsh
(since 1995). Withsetopt localoptions
. Also withemulate -L
for the emulation mode (and its set of options) to be made local to the function.
bash
(since 2016) withlocal -
like inash
.
¹ 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
edited 1 hour ago
answered Jan 10 at 15:29
Stéphane ChazelasStéphane Chazelas
333k58 gold badges652 silver badges1022 bronze badges
333k58 gold badges652 silver badges1022 bronze badges
Bourne (heirloom version) supports functions asf() { list; }
.
– Isaac
Jan 11 at 12:25
1
@Isaac, it'sf() any-command
(except that ifany-command
is a simple command, it can't have redirections). The POSIX syntax isf() 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 kshfunction f { ....}
predated that (ksh first announced in 1983 AFAIK).
– Stéphane Chazelas
Jan 11 at 14:26
add a comment |
Bourne (heirloom version) supports functions asf() { list; }
.
– Isaac
Jan 11 at 12:25
1
@Isaac, it'sf() any-command
(except that ifany-command
is a simple command, it can't have redirections). The POSIX syntax isf() 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 kshfunction 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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Jan 11 at 0:05
community wiki
glenn jackman
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
dash supports them, ksh supports them but I think you need to use
typeset
instead oflocal
– Jesse_b
Jan 10 at 14:18
6
@Jesse_b ksh doesn't support the
local
keyword; it does support local variables, but viatypeset
not via thelocal
, and only in funcs defined asfunction foo { }
, not in funcs defined asfoo(){ }
.– 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 asfoo(){ ... }
? 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