S=2 echo $S echo "$S" bash -c " echo $S " bash -c " echo '$S' " bash -c " echo "$S" " Why do all of these echo the same thing? They all print 2 and I don't understand why.
The most confusing one for me is bash -c " echo '$S' ", since echo '$S' = $S. How come bash -c " echo '$S' " works like the others?
1 Answer
bash -c " echo '$S' "
Because the string " echo '$S' " is double quoted it is being interpolated by the outer shell. The single quotes aren't relevant at this stage. The outer shell expands $S and the resulting command is:
bash -c " echo '2' " Then the inner bash command runs and, as you can see, the string being echoed is the fixed string '2' with no variable.
bash -c " echo "$S" "
This looks like it contains quotes inside of quotes, but looks can be deceiving. What you actually have is " echo " adjacent to $S adjacent to " ".
The result is still 2, but I just wanted to point out that this isn't analogous to the bash -c " echo '$S' " case above, which does have nested quotes.
Follow up case
bash -c ' echo "$S" ' You didn't write this form where the outer quotes are single quotes. If you had, you might be puzzled that it doesn't print 2 like the rest. That's weird. Why not?
Answer: Unlike all the versions you posted, this one has the inner shell doing the expansion of $S. The command is single quoted which prevents the outer shell from expanding it, so $S makes it intact to the inner shell. The inner shell, though, doesn't have a variable called $S, and ends up just printing a blank line.
Why doesn't it have S=2? It's because S was not exported. In order for a variable to be visible in a child process it needs to be exported with
export S=2 or
S=2 export S Unexported variables are only visible in the current process and are unset in child processes.
2