This command:

A=10 echo $A

prints an empty line. Why not 10? Why doesn't the in-place temporary environment setting work?

I want to know the reason and explanation rather than solution.

I used

LANG=C gcc ...

to force gcc use the fallback language (English) instead of the system language (Chinese). So I assume a VAR=value prefix will setup a temporary environment for the command following it. But it looks like I have some misunderstanding.

3 Answers 3


When you use LANG=C gcc ... what happens is that the shell sets LANG for gcc's environment only, and not for the current environment itself (see note). So after gccfinishes, LANG is back to its previous value (or unset).

Additionally, when you use A=10 echo $A it is the shell that replaces $A, not echo, and this substitution (called "expansion") happens before the statement is evaluated (including the assignment), so to work as expected A's value must be already set in the current environment prior to that statement.

That's why A=10 echo $A does not work as expected: A=10 will be set for echo, but echo internally ignores the value of the environment variable A. And $A is replaced with the value set in the current shell (which is none), and then passed as an argument to echo.

So your assumption is correct: VAR=value command does work, but this is only relevant if command internally uses VAR. If not, you can still pass value as an argument to command, but arguments are replaced by the current shell, so they must be set prior to usage: VAR=value; command "$VAR"

If you know how to create an executable script, you can try this as a test:

echo "1st argument is $1"
echo "A is $A"

Save it as testscript and try:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10

Last but not least, it's worth knowing the difference between shell and environment variables and program arguments.

Here are some good references:


(*) Note: technically the shell does set in current environment too, and here's why: Some commands, like echo, read and test are shell builtins, and as such they don't spawn a child process. They run in current environment. But the shell takes care for the assignment only lasts until the command is running, so for all practical purposes the effect is the same: the assignment is only seen by that single command.

  • 2
    This explanation is actually incorrect, although it results in the correct conclusion in all but a few corner cases. The real explanation is the order of expansion: $A is evaluated before the assignment takes place. I think your explanation only fails in the case of regular built-in utilities whose behavior depends on the value of the variable: the built-in does see the assigned value. A common example is IFS=: read one two three rest, which reads colon-separated fields: the read builtin does see the value of IFS. May 29, 2014 at 1:03
  • “not for the current shell itself” is wrong: the variable is set in the current shell, but it only lasts for the current simple command. echo would see the value 10 for A, if it cared. May 30, 2014 at 18:46
  • @Gilles: thanks a lot for the clarification! I wasn't aware of this subtlety. So, if I understood correctly, bash has to set for the current environment otherwise builtins (which don't spawn a new pid) would not see the assignment as other "regurlar" commands would. But it unsets after the command is done to limit the assignment scope. Is this is correct, I'll fix my answer accordingly. PS: technicalities aside, I still think an answer should emphasize on the scope aspect, not evaluation order, otherwise one could think A=10 test; echo $A will print 10
    – MestreLion
    Jun 1, 2014 at 12:31

It's a matter of the order in which the different steps of evaluating a command happen.

A=10 echo $A first parses the command into a simple command made of three words A=10, echo and $A. Then each word undergoes variable substitution, i.e. the transformation of variable expansions such as $A into their values (I'm omitting steps that do nothing visible).

If A has the value foo initially, the result of the expansion steps is a simple command which still has three words: A=10, echo and foo. (The shell also remembers at this point which characters were initially within quotes — in this case, none.) The next step is to execute the command. Since A=10 begins with a valid variable name followed by an equal sign, it is treated as an assignment; the variable A is set to 10 in both the shell and the environment during the execution of the command. (Normally you need to write export A to have A in the environment and not just as a shell variable; this is an exception.) The next word is not an assignment, so it's treated as a command name (it's a built-in command). The echo command does not depend on any variable, so A=10 echo $A has exactly the same effect as echo $A.

If you want to set a variable for the duration of a command only, but taking the assignment into account while executing the command, you can use a subshell. A subshell, indicated by parentheses, makes all state changes (variable assignments, current directory, function definitions, etc.) local to the subshell.

(A=10; echo $A)

Make that export A=10 if you want to export the variable to the environment so that it is seen by external programs.

  • Thanks, can I say A=10 (echo $A) and get 10? May 29, 2014 at 1:16
  • 2
    @EarthEngine No, that would be a syntax error. The assignment has to be at the start of a simple command (i.e. just a command name and some parameters, and optionally some initial assignments and some redirections). A=10; (echo $A) outputs 10 but also sets A for the remainder of the script. May 29, 2014 at 1:35
  • 2
    @EarthEngine But you can say A=10 eval 'echo $A'. The single-quotes stop $A being interpreted until the whole line is evaluated... By which time A=10. I consider this answer more right than the accepted.
    – Oli
    May 29, 2014 at 9:05
  • I think this is the correct explanation. The reason for the behavior is just the order of when the expansion of $A and the assignment of A is happening. E.g. A=5; A=6 let 'a=A'; echo $a returns 6 not 5 and I don't think let starts a subshell, since it's a builtin command. May 29, 2014 at 21:28
  • @EarthEngine: When it's said that the correct explanation is the order of evaluation, it may be misleading: A=10 echo $A will not set A=10 for any commands afterwards, even if they are in different lines (when clearly the assignment was already evaluated). It's not about order, it's about scope
    – MestreLion
    May 30, 2014 at 8:24

One possibly clean way to do what you apparently desire is to issue the command:

A=10 eval 'echo $A'

Which will in effect defer the substitution of the value 10 into the place of $A to a later context (ie, 'inside' the eval, which already knows about the assignment). Note that the single quotes are essential. Such a construct cleanly communicates the assignment to your desired command (echo in this case) without running the risk of polluting your current environment.

Not the answer you're looking for? Browse other questions tagged or ask your own question.