Okay, I learned that one can use &
or &&
to combine multiple commands into a single line, but it seems that variables that are set
aren't actually available for interpolation in the same line:
C:\Users\Andrew>set foo=hello, world!&& echo %foo%
%foo%
C:\Users\Andrew>echo %foo%
hello, world!
Why can't I make this work, and is there any way to make it work in a single line?
The reason I need a one-liner is that an external program I'm working with accepts a single command as a pre-run hook, and, of course, I need to run multiple commands.
"hello, world!
should be surrounded in double-quotes!" Actually, doing so seems to store literal double-quotes in the variable, which I do not want, e.g.
C:\Users\Andrew>set bar="hello, world!"&& echo %bar%
%bar%
C:\Users\Andrew>echo %bar%
"hello, world!"
"There should be a space before the &&
!" Actually, doing so seems to store a trailing space in the variable, which I do not want, e.g.
C:\Users\Andrew>set bar="hello, world!"&& echo %bar%
%bar%
C:\Users\Andrew>echo %bar%
"hello, world!"
"Both!" >:(
C:\Users\Andrew>set mu="hello, world!" && echo %mu%
%mu%
C:\Users\Andrew>echo (%mu%)
("hello, world!" )
To reference a variable in Windows, use %varname% (with prefix and suffix of '%' ). For example, you can use the echo command to print the value of a variable in the form " echo %varname% ".
To pass variable values via the command line, use the PrjVar ( pv ) or PSVar ( psv ) arguments for the project and project suite variables respectively. Variable values you pass via the command line are temporary.
You can do it in the same line, but I would recommend to use a batch file like preHook.bat.
As one liner
set "mu=hello, world!" && call echo %^mu%
At first you can see that the quotes are different than yours.
Here's why:
set test1="quotes"
set "test2=no quotes" with comment
In the first test, the quotes will be part of the test1
variable, as well as all characters after the last quote.
In the second test, it uses the extended syntax of the SET
command.
So the content will be no quotes
, as only the content to the last quote is used; the rest will be dropped.
To echo the variable content, I use call echo %^mu%
, as percent expansion will expand it when the line is parsed, before any of the commands are executed.
But the call
command will be executed later, and it restarts the parser, which, when used at the command line, uses different expansion rules than the batch parser: an empty variable (in this case, %^mu%
, in the first time) stays unchanged in the line; but, in the next parser phase, the ^
caret will be removed.
In your case, call echo %mu%
would also work, but only when mu
is always empty. The caret variant also works when mu
has content before the line is executed.
More about the parser at SO: How does the Windows Command Interpreter (CMD.EXE) parse scripts? And about variable expansion at SO: Variable expansion
Though I accepted @jeb's answer, ultimately I had to go another route, because I needed to pipe the output of my command, and doing so on call
led to mangled results. Indeed, the documentation for call
itself remarks,
Do not use pipes and redirection symbols with call.
Instead, reminded by @Blorgbeard of cmd
's /v
option (and I believe that should be lowercase, not uppercase), I realized I could simply start a subprocess:
C:\Users\Andrew>cmd /v /c "set foo=hello, world!&& echo !foo!"
hello, world!
(For some reason, /v
must appear before /c
.) Within the quotes, I was able pipe my output to other utilities. One tip for those taking this path: If you find yourself needing to use quotes within those quotes, I suggest avoiding them altogether and trying character codes, e.g. \x20
for space, \x22
for double quotes, and so on.
For example, this was the eventual solution to my problem (warning: may cause eyes to bleed):
C:\Users\Andrew>cmd /v /c "set source=C:\source& set target=C:\target& set archive=C:\archive& robocopy.exe !source! !target! /l /e /zb /xx /xl /fp /ns /nc /ndl /np /njh /njs | sed -e s/^^[\t\x20]\+// | sed -e /^^$/d | sed -e s/^!source:\=\\!// | sed -e s/.*/xcopy\x20\/Fvikrhyz\x20\x22!source:\=\\!^&\x22\x20\x22!archive:\=\\!^&\x22/"
Try the following:
cmd.exe /v /c "set foo=hello, world & echo !foo!"
The /v
argument enables delayed variable expansion. This allows you to access variables' values at execution time rather than at parse time (the default). You do this by writing !foo!
instead of %foo%
(with this /v
option turned on).
Instead of passing /v
, you can also turn delayed variable expansion on permanently via the registry, which obviously affects the entire system:
[HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor]
"DelayedExpansion"= (REG_DWORD)
1=enabled 0=disabled (default)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With