Related
I've got a batch script (app1.bat) calling another batch script (app2.bat) which itself calls a program in windows (program.exe).
app2.bat calls program.exe with a parameter after a flag in this way:
program.exe -f Parameter with whitespaces coming into the program
What I want to do is to pass the phrase that comes to program.exe from app1.bat into app2.bat but i don't know how to properly handle the doublequotes. Currently I am passing the phrase from app1.bat to app2.bat in double quotes and inside an app2.bat (prior to executing program.exe) I get rid of the quotes like that:
inside app1.bat
call app2.bat "Parameter with whitespaces coming into the program"
inside app2.bat
set old_phrase=%1%
set new_phrase=%old_phrase:"=%
program.exe -f %new_phrase%
old_phrase is
"Parameter with whitespaces coming into the program"
and new_phrase I end up with is
Parameter with whitespaces coming into the program
Is there any standard way to handle such a situation (being passing a string to an external program which expects a tring without quotes and being ok with whitespaces, whereas batch does not allow for no-quotes-and-whitespaces strings)
When you execute call /? from cmd to launch the help you will see quite a bit around expansion of %n
The first one states:
%~1 - expands %1 removing any surrounding quotes (")
You can therefore dump all the other set commands and simply run this in your batch file:
program.exe -f %~1
The Windows command prompt (cmd.exe) has an optional /s parameter, which modifies the behavior of /c (run a particular command and then exit) or /k (run a particular command and then show a shell prompt). This /s parameter evidently has something to do with some arcane quote handling.
The docs are confusing, but as far as I can tell, when you do cmd /csomething, and the something contains quotation marks, then by default cmd will sometimes strip off those quotes, and /s tells it to leave them alone.
What I don't understand is when the quote removal would break anything, because that's the only time /s ("suppress the default quote-removal behavior") would be necessary. It only removes quotes under a certain arcane set of conditions, and one of those conditions is that the first character after the /c must be a quotation mark. So it's not removing quotes around arguments; it's either removing quotes around the path to the EXE you're running, or around the entire command line (or possibly around the first half of the command line, which would be bizarre).
If the path to the EXE is quoted, e.g. cmd /c "c:\tools\foo.exe" arg1 arg2, then quotes are unnecessary, and if cmd wants to remove them, fine. (It won't remove them if the path has a space in the name -- that's another of the arcane rules.) I can't imagine any reason to suppress the quote removal, so /s seems unnecessary.
If the entire command line is quoted, e.g. cmd /c "foo.exe arg1 arg2", then it seems like quote removal would be a necessity, since there's no EXE named foo.exe arg1 arg2 on the system; so it seems like opting out of quote removal using /s would actually break things. (In actual fact, however, it does not break things: cmd /s /c "foo.exe arg1 arg2" works just fine.)
Is there some subtlety to /s that's eluding me? When would it ever be necessary? When would it even make any difference?
Cmd /S is very useful as it saves you having to worry about "quoting quotes". Recall that the /C argument means "execute this command as if I had typed it at the prompt, then quit".
So if you have a complicated command which you want to pass to CMD.exe you either have to remember CMD's argument quoting rules, and properly escape all of the quotes, or use /S, which triggers a special non-parsing rule of "Strip first and last " and treat all other characters as the command to execute unchanged".
You would use it where you want to take advantage of the capabilities of the CMD shell, rather than directly calling another program. For example environment variable expansion, output or input redirection, or using CMD.exe built-ins.
Example:
Use a shell built-in: This executes as-if you had typed DEL /Q/S "%TMP%\TestFile" at the prompt:
CMD.exe /S /C " DEL /Q/S "%TMP%\TestFile" "
This executes SomeCommand.exe redirecting standard output to a temp file and standard error to the same place:
CMD.exe /S /C " "%UserProfile%\SomeCommand.exe" > "%TMP%\TestOutput.txt" 2>&1 "
So what does /S give you extra? Mainly it saves you from having to worry about quoting the quotes. It also helps where you are unsure whether for example an environtment variable contains quote characters. Just say /S and put an extra quote at the beginning and end.
Vaguely Related: $* in Bourne Shell.
Some background
Recall that the list of arguments to main() is a C-ism and Unix-ism. The Unix/Linux shell (e.g. Bourne Shell etc) interprets the command line, un-quotes the arguments, expands wildcards like * to lists of files, and passes a list of arguments to the called program.
So if you say:
$ vi *.txt
The vi command sees for example these arguments:
vi
a.txt
b.txt
c.txt
d.txt
This is because unix/linux operates internally on the basis of "list of arguments".
Windows, which derives ultimately from CP/M and VAX, does not use this system internally. To the operating system, the command line is just a single string of characters. It is the responsibility of the called program to interpret the command line, expand file globs (* etc) and deal with unquoting quoted arguments.
So the arguments expected by C, have to be hacked up by the C runtime library. The operating system only supplies a single string with the arguments in, and if your language is not C (or even if it is) it may not be interpreted as space-separated arguments quoted according to shell rules, but as something completely different.
Here's an example of how it can make a difference.
Suppose you have two executables: c:\Program.exe and c:\Program Files\foo.exe.
If you say
cmd /c "c:\Program Files\foo"
you'll run foo.exe (with no arguments) whereas if you say
cmd /s /c "c:\Program Files\foo"
you'll run Program.exe with Files\foo as the argument.
(Oddly enough, in the first example, if foo.exe didn't exist, Program.exe would run instead.)
Addendum: if you were to type
c:\Program Files\foo
at the command prompt, you would run Program.exe (as happens with cmd /s /c) rather than foo.exe (as happens with just cmd /c). So one reason for using /s would be if you want to make sure a command is parsed in exactly the same way as if it were being typed at the command prompt. This is probably more likely to be desirable in the scenario in the question Michael Burr linked to, where cmd.exe is being launched by CreateProcess rather than from a batch file or the command line itself..
That is, if you say
CreateProcess("cmd.exe", "cmd /s /c \"" MY_COMMAND "\"", ...)
then the string MY_COMMAND will be parsed exactly as if it were typed at the command prompt. If you're taking command-line input from the user, or if you're a library processing a command line provided by an application, that's probably a good idea. For example, the C runtime library system() function might be implemented in this way.
In all but one specific case, the /S won't actually make any difference.
The help for cmd.exe is accurate, if a bit complicated:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
If all of the following conditions are met, then quote characters
on the command line are preserved:
no /S switch
exactly two quote characters
no special characters between the two quote characters,
where special is one of: &<>()#^|
there are one or more whitespace characters between the
two quote characters
the string between the two quote characters is the name
of an executable file.
Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
I'd summarize as follows:
Normal behavior:
If the rest of the command line after /K or /C starts with a quote, both that quote and the final quote are removed. (See exception below.) Other than that, no quotes are removed.
Exception:
If the rest of the command line after /K or /C starts with a quote, followed by the name of an executable file, followed by another quote, AND if those are the only two quotes, AND if the file name contains spaces but contains no special characters, then the quotes are not removed (even though they normally would have been removed according to the rule above).
The only effect of /S is to override this one exception, so that the two quote characters are still removed in that case.
If you always use /S, you can forget about the exception and just remember the "normal" case. The downside is that cmd.exe /S /C "file name with spaces.exe" argument1 won't work without adding an extra set of quotes, whereas without /S it would have worked... until you decide to replace argument1 with "argument1".
I have a question about the DOS start command.
I have already read this topic:
Using the DOS “start” command with parameters passed to the started program
Using the "start" command with parameters passed to the started program
but my question is a little different.
I have this problem: I need to pass paths that need to be quoted.
For example, if path have no quotes this works fine:
start "" app.exe -option c:\myapp\myfile.txt
but if path have double quotes it doesn't works.
I have this line in my BATCH file:
start "" myapp.exe -option %mypath%
and when %mypath% contains double quotes (paths that have spaces or other characters in names) the start command returns very strange results.
Thanks
Sandro
Normally it's not a problem to use parameters there with quotes, but you get problems if your app-path has also quotes.
Then you need to add an extra CALL statement.
start "" app.exe -option c:\myapp\myfile.txt - Works
start "" app.exe -option "c:\myapp\myfile.txt" - Works
start "" "app.exe" -option c:\myapp\myfile.txt - Works
start "" "app.exe" -option "c:\myapp\myfile.txt" - Don't works
start "" CALL "app.exe" -option "c:\myapp\myfile.txt" - Works
This might help, but it is a bit way round about method and slight modification may required to suit your need.
The idea is to:
Dump the environment variable which has quotes to a text file with a predefined name. Like:"set mypath2 > withQt.bat"
Use windows power shell or some third party tool to find and replace quotes in that file.
Create another text file (one time step only) containing string "Set "
Use copy command to append the file mentioned in step2 with the file created in step3 and create a batch file with a predefined name. Like: copy base.bat + withQt.bat withtqt.bat
Run the batch file, which creates another/replaces the environment variable with value without quotes.
Sorry, I couldn't get something more elegant at this time.
I want to run two commands in a Windows CMD console.
In Linux I would do it like this
touch thisfile ; ls -lstrh
How is it done on Windows?
Like this on all Microsoft OSes since 2000, and still good today:
dir & echo foo
If you want the second command to execute only if the first exited successfully:
dir && echo foo
The single ampersand (&) syntax to execute multiple commands on one line goes back to Windows XP, Windows 2000, and some earlier NT versions. (4.0 at least, according to one commenter here.)
There are quite a few other points about this that you'll find scrolling down this page.
Historical data follows, for those who may find it educational.
Prior to that, the && syntax was only a feature of the shell replacement 4DOS before that feature was added to the Microsoft command interpreter.
In Windows 95, 98 and ME, you'd use the pipe character instead:
dir | echo foo
In MS-DOS 5.0 and later, through some earlier Windows and NT versions of the command interpreter, the (undocumented) command separator was character 20 (Ctrl+T) which I'll represent with ^T here.
dir ^T echo foo
A quote from the documentation:
Source: Microsoft, Windows XP Professional Product Documentation, Command shell overview
Also: An A-Z Index of Windows CMD commands
Using multiple commands and conditional processing symbols
You can run multiple commands from a single command line or script using conditional processing symbols. When you run multiple commands with conditional processing symbols, the commands to the right of the conditional processing symbol act based upon the results of the command to the left of the conditional processing symbol.
For example, you might want to run a command only if the previous command fails. Or, you might want to run a command only if the previous command is successful.
You can use the special characters listed in the following table to pass multiple commands.
& [...]
command1 & command2
Use to separate multiple commands on one command line. Cmd.exe runs the first command, and then the second command.
&& [...]
command1 && command2
Use to run the command following && only if the command preceding the symbol is successful. Cmd.exe runs the first command, and then runs the second command only if the first command completed successfully.
|| [...]
command1 || command2
Use to run the command following || only if the command preceding || fails. Cmd.exe runs the first command, and then runs the second command only if the first command did not complete successfully (receives an error code greater than zero).
( ) [...]
(command1 & command2)
Use to group or nest multiple commands.
; or ,
command1 parameter1;parameter2
Use to separate command parameters.
& is the Bash equivalent for ; ( run commands) and && is the Bash equivalent of && (run commands only when the previous has not caused an error).
If you want to create a cmd shortcut (for example on your desktop) add /k parameter (/k means keep, /c will close window):
cmd /k echo hello && cd c:\ && cd Windows
You can use & to run commands one after another. Example: c:\dir & vim myFile.txt
You can use call to overcome the problem of environment variables being evaluated too soon - e.g.
set A=Hello & call echo %A%
A number of processing symbols can be used when running several commands on the same line, and may lead to processing redirection in some cases, altering output in other case, or just fail. One important case is placing on the same line commands that manipulate variables.
#echo off
setlocal enabledelayedexpansion
set count=0
set "count=1" & echo %count% !count!
0 1
As you see in the above example, when commands using variables are placed on the same line, you must use delayed expansion to update your variable values. If your variable is indexed, use CALL command with %% modifiers to update its value on the same line:
set "i=5" & set "arg!i!=MyFile!i!" & call echo path!i!=%temp%\%%arg!i!%%
path5=C:\Users\UserName\AppData\Local\Temp\MyFile5
cmd /c ipconfig /all & Output.txt
This command execute command and open Output.txt file in a single command
So, I was trying to enable the specific task of running RegAsm (register assembly) from a context menu. The issue I had was that the result would flash up and go away before I could read it. So I tried piping to Pause, which does not work when the command fails (as mentioned here Pause command not working in .bat script and here Batch file command PAUSE does not work). So I tried cmd /k but that leaves the window open for more commands (I just want to read the result). So I added a pause followed by exit to the chain, resulting in the following:
cmd /k C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe "%1" /codebase \"%1\" & pause & exit
This works like a charm -- RegAsm runs on the file and shows its results, then a "Press any key to continue..." prompt is shown, then the command prompt window closes when a key is pressed.
P.S. For others who might be interested, you can use the following .reg file entries to add a dllfile association to .dll files and then a RegAsm command extension to that (notice the escaped quotes and backslashes):
[HKEY_CLASSES_ROOT\.dll]
"Content Type"="application/x-msdownload"
#="dllfile"
[HKEY_CLASSES_ROOT\dllfile]
#="Application Extension"
[HKEY_CLASSES_ROOT\dllfile\Shell\RegAsm]
#="Register Assembly"
[HKEY_CLASSES_ROOT\dllfile\Shell\RegAsm\command]
#="cmd /k C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe \"%1\" /codebase \"%1\" & pause & exit"
Now I have a nice right-click menu to register an assembly.
In windows, I used all the above solutions &, && but nothing worked
Finally ';' symbol worked for me
npm install; npm start
Well, you have two options: Piping, or just &:
DIR /S & START FILE.TXT
Or,
tasklist | find "notepad.exe"
Piping (|) is more for taking the output of one command, and putting it into another. And (&) is just saying run this, and that.
In order to execute two commands at the same time, you must put an & (ampersand) symbol between the two commands. Like so:
color 0a & start chrome.exe
Cheers!
I try to have two pings in the same window, and it is a serial command on the same line. After finishing the first, run the second command.
The solution was to combine with start /b on a Windows 7 command prompt.
Start as usual, without /b, and launch in a separate window.
The command used to launch in the same line is:
start /b command1 parameters & command2 parameters
Any way, if you wish to parse the output, I don't recommend to use this.
I noticed the output is scrambled between the output of the commands.
Use & symbol in windows to use command in one line
C:\Users\Arshdeep Singh>cd Desktop\PROJECTS\PYTHON\programiz & jupyter notebook
like in linux
we use,
touch thisfile ; ls -lstrh
I was trying to create batch file to start elevated cmd and to make it run 2 separate commands.
When I used & or && characters, I got a problem. For instance, this is the text in my batch file:
powershell.exe -Command "Start-Process cmd \"/k echo hello && call cd C:\ \" -Verb RunAs"
I get parse error:
After several guesses I found out, that if you surround && with quotes like "&&" it works:
powershell.exe -Command "Start-Process cmd \"/k echo hello "&&" call cd C:\ \" -Verb RunAs"
And here's the result:
May be this'll help someone :)
No, cd / && tree && echo %time%. The time echoed is at when the first command is executed.
The piping has some issue, but it is not critical as long as people know how it works.
One more example: For example, when we use the gulp build system, instead of
gulp - default > build
gulp build - build build-folder
gulp watch - start file-watch
gulp dist - build dist-folder
We can do that with one line:
cd c:\xampp\htdocs\project & gulp & gulp watch
Yes there is. It's &.
&& will execute command 2 when command 1 is complete providing it didn't fail.
& will execute regardless.
With windows 10 you can also use scriptrunner:
ScriptRunner.exe -appvscript demoA.cmd arg1 arg2 -appvscriptrunnerparameters -wait -timeout=30 -rollbackonerror -appvscript demoB.ps1 arg3 arg4 -appvscriptrunnerparameters -wait -timeout=30 -rollbackonerror
it allows you to start few commands on one line you want you can run them consecutive or without waiting each other, you can put timeouts and rollback on error.
Try to create a .bat ot .cmd file with those lines using doskey key and $T which is equivalent to & to do several command line in just one line :
touch=echo off $T echo. ^> $* $T dir /B $T echo on
It'll create an empty file.
Example:
touch myfile
In cmd you'll get something like this:
But as mentioned previously by others, it is really advised to use & operator to do many command line in one line from CMD prompt.
Enjoy =)
When you try to use or manipulate variables in one line beware of their content! E.g. a variable like the following
PATH=C:\Program Files (x86)\somewhere;"C:\Company\Cool Tool";%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;
may lead to a lot of unhand-able trouble if you use it as %PATH%
The closing parentheses terminate your group statement
The double quotes don't allow you to use %PATH% to handle the parentheses problem
And what will a referenced variable like %USERPROFILE% contain?
It's simple: just differentiate them with && signs.
Example:
echo "Hello World" && echo "GoodBye World".
"Goodbye World" will be printed after "Hello World".
In a Windows batch file, when you do the following:
set myvar="c:\my music & videos"
the variable myvar is stored with the quotes included. Honestly I find that very stupid. The quotes are just to tell where the string begins and ends, not to be stored as part of the value itself.
How can I prevent this from happening?
Thanks.
set "myvar=c:\my music & videos"
Notice the quotes start before myvar. It's actually that simple.
Side note: myvar can't be echoed afterwards unless it's wrapped in quotes because & will be read as a command separator, but it'll still work as a path.
http://ss64.com/nt/set.html under "Variable names can include Spaces"
This is the correct way to do it:
set "myvar=c:\my music & videos"
The quotes will not be included in the variable value.
It depends on how you want to use the variable. If you just want to use the value of the variable without the quotes you can use either delayed expansion and string substitution, or the for command:
#echo OFF
SETLOCAL enabledelayedexpansion
set myvar="C:\my music & videos"
As andynormancx states, the quotes are needed since the string contains the &. Or you can escape it with the ^, but I think the quotes are a little cleaner.
If you use delayed expansion with string substitution, you get the value of the variable without the quotes:
#echo !myvar:"=!
>>> C:\my music & videos
You can also use the for command:
for /f "tokens=* delims=" %%P in (%myvar%) do (
#echo %%P
)
>>> C:\my music & videos
However, if you want to use the variable in a command, you must use the quoted value or enclose the value of the variable in quotes:
Using string substitution and delayed expansion to use value of the variable without quotes, but use the variable in a command:
#echo OFF
SETLOCAL enabledelayedexpansion
set myvar="C:\my music & videos"
md %myvar%
#echo !myvar:"=! created.
Using the for command to use the value of the variable without quotes, but you'll have to surround the variable with quotes when using it in commands:
#echo OFF
set myvar="C:\my music & videos"
for /f "tokens=* delims=" %%P in (%myvar%) do (
md "%%P"
#echo %%P created.
)
Long story short, there's really no clean way to use a path or filename that contains embedded spaces and/or &s in a batch file.
Use jscript.
Many moons ago (i.e. about 8 years give or take) I was working on a large C++/VB6 project, and I had various bits of Batch Script to do parts of the build.
Then someone pointed me at the Joel Test, I was particularly enamoured of point 2, and set about bringing all my little build scripts into one single build script . . .
and it nearly broke my heart, getting all those little scripts working together, on different machines, with slightly different setups, ye Gods it was dreadful - particularly setting variables and parameter passing. It was really brittle, the slightest thing would break it and require 30 minutes of tweaking to get going again.
Eventually - I can be stubborn me - I chucked the whole lot in and in about a day re-wrote it all in JavaScript, running it from the command prompt with CScript.
I haven't looked back. Although these days it's MSBuild and Cruise Control, if I need to do something even slightly involved with a batch script, I use jscript.
The Windows command interpreter allows you to use the quotes around the entire set command (valid in every version of windows NT from NT 4.0 to Windows 2012 R2)
Your script should just be written as follows:
#echo OFF
set "myvar=C:\my music & videos"
Then you may put quotes around the variables as needed.
Working with the CMD prompt can seem esoteric at times, but the command interpreter actually behaves pretty solidly in obeying it's internal logic, you just need to re-think things.
In fact, the set command does not require you to use quotes at all, but both the way you are doing your variable assignment and the way the ,method of using no quotes can cause you to have extra spaces around your variable which are hard to notice when debugging your script.
e.g. Both of the below are technically Valid, but you can have trailing spaces, so it's not a good practice:
set myvar=some text
set myvar="some text"
e.g. Both of the below are good methods for setting variables in Windows Command interpreter, however the double quote method is superior:
set "myvar=Some text"
(set myvar=Some value)
Both of these leave nothing to interpretation the variable will have exactly the data you are looking for.
strong text However, for your purposes, only the quoted method will work validly because you are using a reserved character
Thus, you would use:
set "myvar=c:\my music & videos"
However, even though the variable IS correctly set to this string, when you ECHO the sting the command interpreter will interpret the ampersand as the keyword to indicate another statement follows.
SO if you want to echo the string from the variable the CMD interpreter still needs to be told it's a text string, or if you do not want the quotes to show you have to do one of the following:
echo the variable WITH Quotes:
Echo."%myvar%"
echo the variable WITHOUT Quotes:
Echo.%myvar:&=^&%
<nul SET /P="%myvar%"
In the above two scenarios you can echo the string with no quotes just fine. Example output below:
C:\Admin> Echo.%myvar:&=^&%
C:\my music & videos
C:\Admin> <nul SET /P="%myvar%"
C:\my music & videos
C:\Admin>
Try using the escape character '^', e.g.
set myvar=c:\my music ^& videos
You'll have you be careful when you expand myvar because the shell might not treat the & as a literal. If the above doesn't work, try inserting a caret into the string too:
set myvar=c:\my music ^^^& videos
Two solutions:
Don't use spaces or other characters that are special to the command interpreter in path names (directory or file names). If you use only letters, numbers, underscores, and hyphens (and a period before the extension to identify the file type), your scripting life will become immeasurably simpler.
I have written and otherwise collected a plethora of tools over the years, including a DOS utility that will rename files. (It began as something that just removed spaces from filenames, but morphed into something that will replace characters or strings within the filenames, even recursively.) If anyone's interested, I will get my long-neglected web site up and running and post this and others.
That said, variables aren't just for holding pathnames, so...
As others have already pointed out, SET "myvar=c:\my music & videos" is the correct workaround for such a variable value. (Yes, I said workaround. I agree that your initial inclination to just quote the value ("my music & videos") is far more intuitive, but it is what it is, as they say.