Assigning and using a variable in the same subshell

I did something very simple: v=5 echo "$v" and expected it to print 5 . However, it is not. The value that was just set is not available for the next command.

I recently found out : "In most shells, each pipeline command is executed in a separate SubShell." However, in this case, both commands are executed in the same subshell.

Why is this happening? Is there any way to make this work?

Full example:

 $ v=1 $ v=5 echo "$v" 1 # I expected 5! 
+7
scope bash subshell
source share
3 answers

Look at the POSIX specification to see why , it behaves the same way as not in bash, but in any compatible shell:


2.10.2, Shell Grammar Rules

From rule 7 (b), covering cases where an assignment precedes a simple instruction:

If all characters preceding '=' form a valid name (see the "Basic Definitions" section of IEEE Std 1003.1-2001, section 3.230, "Name"), the ASSIGNMENT_WORD token is returned. (The quoted characters cannot participate in the formation of the correct name.)

[...]

NAME assignment should be performed as indicated in simple commands.

Therefore, parsing this destination is required for a POSIX compatible shell.


2.9.1, Simple Commands

  1. Redirects should be performed as described in the Redirection section.

  2. Each assignment to a variable must be expanded to expand the tilde, expand the parameters, substitute commands, expand arithmetic, and delete quotes before assigning a value.

[...]

If the command name does not appear, variable assignments affect the current runtime. Otherwise, variable assignments should be exported for the command execution environment and should not affect the current execution environment (with the exception of special built-in modules). If any of the variable assignments tries to assign the value to the variable read-only, a variable assignment error occurs. See โ€œConsequences of Shell Errorsโ€ for the consequences of these errors.

Thus: the assignment given by the prefix part for a simple command should be exported and should not affect the current shell environment, unless the called shell is a special built-in shell. Moreover, these steps should follow the redirects, which by their nature should occur at the end of the command invocation process.


2.12 shell runtime

Utilities other than special built-in modules (see Special built-in utilities) must be called in a separate environment, which consists of the following. The initial value of these objects must be the same as for the parent shell, except as noted below.

[...]

Variables with an export attribute, along with those explicitly exported throughout the command, must be passed to environment variables


Thus: These variables are expanded by subsell after fork and before the invocation of the invoked command, and should, by specification, only affect the child environment.


Now, for some other behavior:

 v=5 sh -c 'echo "$v"' 

... benefits from an instance of sh creating shell variables from its environment variables (as required in section 2.5.3 of the POSIX specification) at startup.


It is worth noting, by the way, that the syntax you are asking for is intended for assignment in a simple command, and not for assignment inside a subshell. You can control the assignment in the subshell associated with the pipeline as follows:

 { v=5; echo "$v"; } | somecommand ... 

... which puts the assignment in a subshell that starts the first component of the pipeline (if your shell really works with this component in the subshell, which is undefined behavior, since POSIX concerns, from the specification: "as an extension, however, any or all of the commands in the pipeline can be executed in the current environment " ).

+4
source share

Simply put, "$ v" is evaluated before the command is invoked, while before the "v = 5" command, the environment of the command being executed changes before the command.

As Charles Duffy said, you can add an intermediate โ€œshโ€ process that will evaluate the variable with similar syntax, but you probably want to do something more complex, and it would be useful to know that if you still have problems with him.

+6
source share
 v=5 echo $v 

will add v = 5 to the environment variables and then execute echo $v . $v refers to the shell variable v that you set on the first line.

Adding the half-bell v=5;echo $v sets the shell variable to 5, and then executes the command after the semicolon, i.e. echo $v , and produces 5.

Try the following command:

 v=5 env|less 

and look at the environment.

+2
source share

All Articles