Normal command chaining methods work normally, for instance:
$ (SCRATCH='heya'; echo $SCRATCH)
heya
Or using the logic operator && yields predictable results:
$ (SCRATCH='heya' && echo $SCRATCH)
heya
But if we chain the commands by using a space then things get weird:
$ (SCRATCH='heya' echo $SCRATCH)
<<just a blank line prints here>>
Despite the above, the variable actually WAS set, and I can prove it with this line:
$ (DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u $USER)/bus" grdctl status)
RDP:
Status: enabled
TLS certificate: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.crt
TLS key: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.key
View-only: no
Username: (hidden)
Password: (hidden)
The above has NO SEMICOLON separating the two commands, and weirdly enough it actually somehow reads the variable and works.
More weirdly, I can break it by inserting the normal requisite semicolon ; which really ought to be there, like this:
$ (DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u $USER)/bus"; grdctl status)
Failed to lookup legacy VNC password schema: Cannot autolaunch D-Bus without X11 $DISPLAY
Failed to lookup RDP credentials: Cannot autolaunch D-Bus without X11 $DISPLAY
Next, leaving the offending semicolon in place... I can bring it back to life by exporting the variable, which makes me think that the grdctl command punts itself into a subshell:
$ (export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u $USER)/bus"; grdctl status)
RDP:
Status: enabled
TLS certificate: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.crt
TLS key: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.key
View-only: no
Username: (hidden)
Password: (hidden)
And yet, if we directly run the following space separated commands directly, then the variable disappears into the ether without a trace, not even any errors!
$ SCRATCH='heya' echo $SCRATCH
<<just a blank line prints here>>
And if I export the variable, then it gets worse and doesn't even print a blank line!
$ export SCRATCH='heya' echo $SCRATCH
<<nothing shows here, not even a blank line now>>
#And again for good measure, same result:
$ export SCRATCH='heya' echo $SCRATCH
<<still nothing, same as before>>
#But yeah, the variable did export to my shell because:
$ echo $SCRATCH
heya
So not only does the semicolon send make the variable unreachable by echo, but it also prevents echo from seeing the parent environment!
And it's not just the built-in echo command that's hosed, printf is sick too:
$ EPHEMERAL='blink' printf "$EPHEMERAL\n"
<<again, a suffocated blank line here>>
But the grdctl command, which is a binary file (neither a script nor a built-in) is perfectly happy to ingest my variable sans semicolon, and output correctly:
$ unset DBUS_SESSION_BUS_ADDRESS
$ DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u $USER)/bus" grdctl status
RDP:
Status: enabled
TLS certificate: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.crt
TLS key: /home/guest/.local/share/gnome-remote-desktop/rdp-tls.key
View-only: no
Username: (hidden)
Password: (hidden)
The above seems extremely inconsistent behavior, in that the echo command behaves one way, while the grdctl behaves another way.
I've googled incessantly and consulted with AI's but nobody can explain the chaining of commands with spaces, which is definitely "a thing" because it often works.
There are tens of thousands of explanations on the Internet about how ; or && or || can be used to chain commands, but not a peep about the space character.
-------------- MY FINAL UPDATE --------------
Okay based on all the good discussions below, here is workaround #1:
$ YUCK=pid; YUCK=stu sh -c 'echo -n $YUCK';echo $YUCK
And here is workaround #2:
$ echo 'printf $SOMEVAR"\n"' > myscript.sh; chmod u+x myscript.sh
$ SOMEVAR='blink' ./myscript.sh
Clearly some commands require workarounds while others don't.
The fact is that bash is allowing an exported temporary env var to be defined "on the fly" before a command to be executed.
Example:
Now let's execute it with a prefixed env var definition
will output:
but
$MY_ENV_VARscope only exists during the call (assuming it wasn't set before)should be empty
Some explanations here:
https://www.baeldung.com/linux/set-env-variables-bash-command
Official documentation here
https://www.gnu.org/software/bash/manual/html_node/Environment.html
The paragraph:
So yes it's a confusing syntax. The missing semi-colon is on purpose here for this specific syntax, that just work for envvar assignment.
A semi-colon would produce a distinct behavior: 2 instructions. So defining the variable, not necessary also exporting it, then executing the command (eventually expanding the variable before the second instruction is executed)
What about
EPHEMERAL='blink' printf "$EPHEMERAL\n"...prints nothing?Well, temporary envvar export could be explained as the following pseudo-code:
but all-in-one!
that mean the
export EPHEMERAL='blink'is not yet available when the all-in-one is evaluated.So when the
printf "$EPHEMERAL\n"is evaluated (not called yet) value is whatever it would before the export will happen. Then, the command is called with the argument and also the envvar becomes available as$EPHEMERAL(with valueblinkduring the call)One was missing and I was curious about it, and I finally got it:
What about
export SCRATCH='heya' echo $SCRATCHprints nothing even if$SCRATCHhas an old value.exportis a built-in command, that takes as argument some variable(s) name and change their export status. It can take multiple argument with and without assignment. It outputs nothing and mostly always returns$?0 (success) even on assignment with errorsv=$(false). It only returns failure status on rare use-case where the assignment is failing: like invalid variable name, system failure like out of memory, or readonly variable assignment, etc. See: SC2155So
export SCRATCH='heya' echo $SCRATCHis decomposing in the following pseudo-code, still all-in-one. ⚠️ Note: that this is not recognized as an augmented-temporarily-by-prefixing-it-with-parameter as it's evaluated as a command.tricky enough?
You can watch the result with this extra command:
What will it output if you run
export SCRATCH='heya' echo $SCRATCHtwice? (left as an exercise for the reader)tested with bash version 5.1.16 (See also bash link above ⬆️ for official manual section: 3.7.4 Environment)
Hope that helps, keep reading the doc, and may be look at shellcheck, you would probably learn many more trick.
Want to become a command line warrior? may this site is still contributed
https://www.commandlinefu.com/commands/browse/sort-by-votes