Re: Export command
- From: Stephane CHAZELAS <this.address@xxxxxxxxxx>
- Date: Sat, 11 Aug 2007 12:11:00 GMT
2007-08-10, 21:44(-00), nits:
Where are the variables exported stored (file)?[...]
What is its difference from declare -x ?
exporting a shell variable means marking that shell variable as
being one that is passed as the "environment" argument of
future execve(2) system calls.
The environment on Unix is a list of strings passed from command
to command upon execution, exactly like the argument list
(argv), except that by convention those strings have the format
"var=value" (that is they contain an "=" sign in 2nd or above
position (though nothing prevents you from not putting any "="
sign or putting it in first position), so that the part before
the first "=" is called an environment variable name and the
part after it is called its value) and that, again by convention,
applications when executing other commands, pass the environment
that they themselves received when they were executed, to the
execve(2) system call that execute the other commands.
For applications other than shells (that have a special
relationship with the environment as they are the tools made to
execute commands), those conventions are made more systematic
by the C library. The C library maintains a /copy/ of the
environment received upon execution (in the "environ" array),
that array can be altered by the setenv(3), putenv(3) functions
and that array is passed to the execve(2) system call when the
execv(3), execl(3)... wrapper functions are used, so that most
commands (as most commands use the C library, and use them that
way), when they do execute other commands pass the environment
as is across executions.
For shells, it's a bit special, given that shells have variables
of their own that you may use in script to store values.
Upon startup, shells create a shell variable for every
environment string they received that are of the format
"xxx=yyy" where "xxx" is a possible shell variable name. So a
shell variable is created for every environment variable.
After that, behaviors differ from shell to shell.
In the Bourne shell (the ancestor of modern sh's), the
environment variables and the shell variables were separate
(even those shell variables created from the environment ones).
You used to use "export" to mark a shell variable as
"exportable", that is one to be passed in the environment of
future commands, and you needed to do that even for variables
created from environment ones if you wanted that the
modifications you made to the shell variables affected the
environment passed to further commands. Otherwise, upon
execution of commands, the variables would be passed as the
shell received them to the executed command.
In modern sh's, shell variables created from environment
variables are automatically marked "exportable". That means that
if you modify a shell variable that was in the environment
received by the shell, commands executed by the shell will
inherit those modifications even if you don't call export for
them. That can be considered as a feature but can also be seed
as an anoyance as most of the time that behavior is not needed
and a shell script can sometimes unintentionnaly modify a
variable that was intended for some other process (that's why
it's often advised to use upper-case variable names for
environment variables and lower-case for shell variables to
avoid clashes).
"declare" is a built-in command of the bash shell only (though
zsh provides it as well for convenience for bash users), most
other shells have typeset instead that comes from ksh for the
same thing. The Bourne shell had only one type of variable, that
could be made exportable or not, so only the "export" command
was needed. ksh introduced other kinds of attributes for a
variable (like "interger", "zero-padded", "read-only") so
instead of introducing a new command for every attribute, it
introduce the "typeset" command so you can use "typeset -i" for
integer, typeset -Z3 for zero-padded... Bash, which to simplify
is mostly an unfinished clone of ksh with csh extensions did the
same but with the "declare" command (though it provides with
typeset as well for compatibility with ksh).
Both typeset and declare have -x for a synonym of export, they
do exactly the same: mark the shell variable as exportable to
future commands.
Also note that the syntax in the Bourne shell was:
export var1 [var2 [var3...]]
Modern shells allow you to assign a value to a variable and
export it at the same time:
export var1=value var2=value
But beware of it. Those commands are not parsed the same way in
all the shells. "export" is meant to be a built in command, so
an export command line is meant to be parsed as a normal command
line which is different from an assignment. But shells like bash
and some implementations of ksh are not POSIX conformant in that
they parse it in some sort of special assigment command
(different from a simple command line, and different from a
simple variable assignment), so I tend to avoid that.
Note that using export is not the only way to pass environment
variables to a command in shell.
The syntax
var=value cmd arg1 arg2
Is a way to pass the var *environment* variable with value
"value" to the "cmd" command (and only that execution of that
command)
Be wary of that syntax though for shell built-in commands. For
what POSIX calls special built-in commands (and in the Bourne
shell every built in command), as in that case, the effect is to
define the corresponding *shell* variable even for the rest of
the script. An effect of that is that
var=value export var
is a correct (and portable) way to define the value of the shell
variable "var" and to make it exportable at the same time.
Note that the Bourne shell used to have an option (set -k) that
allowed to but the environement setting anywhere on the line.
set -k
cmd arg1 a=10 arg2
would start cmd with ["cmd", "arg1", "arg2"] as its argument
list and [<environ>, "a=10"] (in any order) as the environ list.
A note should be added about the "unset" command. That command
didn't exist in early versions of the Bourne shell.
In modern shells, it undefines the corresponding shell variable,
and if that variable was exportable (including if it was created
from the environment received by the shell), it also removes it
from the environment to be passed to future commands. It is also
true of some newer versions of the Bourne shell even for
variables that have not been made exportables.
Some examples on Solaris (one of the rare Unices that still have
a Bourne shell):
With the Bourne shell (/bin/sh):
$ var=value sh -c 'var=foo; env' | grep '^var'
var=value
$ var=value sh -c 'var=foo; export var; env' | grep '^var'
var=foo
$ var=value sh -c 'export var; var=foo; env' | grep '^var'
var=foo
$ var=value sh -c 'export var; unset var; env' | grep '^var'
$ var=value sh -c 'unset var; env' | grep '^var'
$
With a normal sh (/usr/xpg4/bin/sh):
$ var=value sh -c 'var=foo; env' | grep '^var'
var=foo
$ var=value sh -c 'var=foo; export var; env' | grep '^var'
var=foo
$ var=value sh -c 'export var; unset var; env' | grep '^var'
$ var=value sh -c 'unset var; env' | grep '^var'
$
--
Stéphane
.
- References:
- Export command
- From: nits
- Export command
- Prev by Date: Re: Help!
- Next by Date: Re: Regarding file access permision
- Previous by thread: Re: Export command
- Next by thread: Help to optimize this
- Index(es):
Relevant Pages
|