1

Is the global scope the same as the environment?

The declare builtin has a -g option:

The -g option forces variables to be created or modified at the global scope, even when declare is executed in a shell function. It is ignored in all other cases.

Roland
  • 7,525
  • 13
  • 61
  • 124
  • 1
    This is *almost* a duplicate of [Difference between shell and environment variables](https://stackoverflow.com/questions/3341372/difference-between-shell-and-environment-variables). – Charles Duffy Mar 10 '20 at 15:19

1 Answers1

4

TL;DR The global scope is initialized from the environment at startup, but is not the same as the environment.


The environment is a set of strings of the form <name>=<value> provided by the parent process. On startup, the shell takes each string whose <name> portion is a valid shell identifier and creates a variable in the global scope with that name.

For example, an environment string FOO=3 becomes a shell variable named FOO with the value 3.

On the other hand, an environment string like 10=6 is ignored by the shell, because 10 is not a valid shell identifier. The string remains in the environment, though, to be passed on to any child processes that might expect such a string. [UPDATE: The POSIX spec does not require such strings to be ignored; a conforming shell could either keep or discard them.]

There are also local variables, created by commands like local and declare inside a function definition. For example:

$ foo () { declare x; x=3; echo "$x"; }
$ x=2
$ foo
3
$ echo "$x"
2

x=2 created (or changed the value of) a variable in the global scope. Inside the function, declare x created a local variable. Changes to that variable did not affect the global by the same name.

The -g option to declare lets you make the name x inside the function refer to the global scope, rather than creating a local variable.

$ foo () { declare -g x; x=3; echo "$x"; }
$ x=2
$ foo
3
$ echo "$x"
3
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Whether environment variables with invalid names are discarded by the shell (unset from the environment, not just ignored when translating to shell variables) is version-dependent and unspecified by POSIX. We have a question in the knowledgebase about it -- at least some of them started being unset by bash in the early post-shellshock era. – Charles Duffy Mar 10 '20 at 15:14
  • 1
    ...here we are: https://stackoverflow.com/questions/36989263/why-cant-environment-variables-with-dashes-be-accessed-in-bash-4-1-2 – Charles Duffy Mar 10 '20 at 15:15
  • "[...]; applications shall tolerate the presence of such names." seems like a pretty clear indication that names should not be removed from the environment just because the *shell* (or other POSIX utilities) can't use them. – chepner Mar 10 '20 at 15:19
  • Keep reading. *It is unspecified whether environment variables that were passed to the shell when it was invoked, but were not used to initialize shell variables (see Shell Variables) because they had invalid names, are included in the environment passed to execl() and (if execl() fails as described above) to the new shell.* That's from the shell command language spec, not the environment variable spec. – Charles Duffy Mar 10 '20 at 15:20
  • Ugh. That seems unnecessarily weaselly on the part of the POSIX spec. – chepner Mar 10 '20 at 15:24
  • I noted that `zsh` and `dash` do, indeed, strip a string like `10=6` from the environment before forking a child; `bash` and `ksh` do not. – chepner Mar 10 '20 at 15:30