Why does "A=10 echo $A" not print 10?

Solution 1:

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:

#!/bin/sh
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
5

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

Here are some good references:

  • How To Read and Set Environmental and Shell Variables on a Linux VPS

  • Understanding Unix shells and environment variables

.

(*) 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.

Solution 2:

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.

Solution 3:

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.