Hi I have this little command to copy files in a batch, which will help because I do this specific copy multiple times a day. The problem occurs while using the xcopy command. Everything is in order, but I am receiving this error: "Invalid path 0 files copied". Here is the code:
C:\Windows\System32\xcopy /Y "C:\Users\Ryan\Desktop\mmars_pub\" "C:\Users\Ryan\Desktop\Dropbox\MMARS\mmars_pub\"
I'm using the full path to the xcopy executable because I was having trouble configuring the path environment variable to function properly. I would imagine that it shouldn't affect the result though. I read somewhere about the "Prevent MS-DOS-based programs from detecting Windows" checkbox that should fix the issue, but I just can't seem to find that. Any help appreciated.
Original answer
Remove the ending backslash from the source folder path
C:\Windows\System32\xcopy.exe /Y "C:\Users\Ryan\Desktop\mmars_pub" "C:\Users\Ryan\Desktop\Dropbox\MMARS\mmars_pub\"
edited 2015/10/01
While the original question used a literal path, and the indicated solution will solve the problem, there is another option. For literal paths and in cases where the path is inside a variable and could (or not) end in a backslash, it is enough to ensure that the ending backslash (if present) is separated from the quote, including an ending dot.
xcopy /y "x:\source\." "x:\target"
xcopy /y "%myVariable%." "x:\target"
This ending dot will not interfere in files/folders names. If there is and ending backslash, the additional dot will simply refer to the same folder. If there is not ending backslash as in windows files and folders can not end their names with a dot, it will be discarded.
BUT if the output of the xcopy command will be processed, remember that this additional dot will be included in the paths shown.
note: The solutions are above the line. Keep reading if interested on why/where there is a problem.
Why xcopy "c:\source\" "d:\target\" fails but xcopy "c:\source" "d:\target\" works?
Both commands seems to have valid path references, and ... YES! both are valid path references, but there are two elements that work together to make the command fail:
the folder reference is quoted (note: it should be quoted, it is a good habit to quote paths as you never know when they will contain spaces or special characters)
xcopy is not an internal command handled by cmd but an executable file
As xcopy is an external command, its arguments are not handled following the cmd parser command line logic. They are handled by the Microsoft C startup code.
This parser follows two sets of rules, official rules
Arguments are delimited by white space, which is either a space or a tab.
A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted
string can be embedded in an argument. Note that the caret (^) is not
recognized as an escape character or delimiter.
A double quotation mark preceded by a backslash, \", is interpreted as a literal double quotation mark (").
Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
If an even number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every
pair of backslashes (\\), and the double quotation mark (") is
interpreted as a string delimiter.
If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every
pair of backslashes (\\) and the double quotation mark is interpreted
as an escape sequence by the remaining backslash, causing a literal
double quotation mark (") to be placed in argv.
and undocumented/non official rules (How Command Line Parameters Are Parsed)
Outside a double quoted block a " starts a double quoted block.
Inside a double quoted block a " followed by a different character (not another ") ends the double quoted block.
Inside a double quoted block a " followed immediately by another " (i.e. "") causes a single " to be added to the output, and the
double quoted block continues.
This parser sees the sequence \" found at the end of the "first" argument as a escaped quote that does not end/closes the argument, it is seen as part or the argument. And the "starting" quote of the "second" argument is just ending the double quoted block BUT not ending the argument, remember that arguments are delimited by white space.
So while it seems that the command line arguments are
v v v......argument delimiters
v.........v v..........v ......quoted blocks
xcopy "x:\souce\" "x:\target\"
^.......^ ^........^ ......argument data
arg #1 arg #2
arg #1 = x:\source\
arg #2 = x:\target\
the actual argument handled by xcopy is
v v .....argument delimiters
v......................v .....quoted block
xcopy "x:\souce\" "x:\target\"
^.....................^ .....argument data
arg #1
arg #1 = x:\source" x:\target"
When the ending backslash is removed or the additional dot included, the closing quote in the argument will not be escaped, it will close the quoted block and the space between arguments will be seen as a delimiter.
Related
I'm trying to navigate down to a subfolder in a bash shell. The name of the subfolder is:
Let's Go Play!
I cannot figure out how to escape the single quote (apostrophe) or the exclamation point.
I have tried
cd "Let's Go Play\!"
cd "Let\'s Go Play\!"
Thanks.
The correct form is
cd "Let's Go Play!"
Inside double quotes, backslashes are not special unless they come before a newline, a quote, a backslash, a dollar sign or a backtick. Backslash-newline is removed altogether; a backslash followed by one of the other four characters in that list is removed and the character loses its special significance.
Inside single quotes, backslashes are never removed and have no special significance. Consequently, it is impossible to insert a single quote into a single-quoted string and so there is no single-quoted form of the above cd command. However, you can concatenate words, so you could write:
cd 'Let'"'"'s Go Play!'
Outside of quoted words, backslashes are more general. A backslash followed by any character other than a newline character is removed from the input and the following character becomes an ordinary character (even if it were ordinary already). Backslash-newline is removed entirely from the input, so that there is no way to insert a newline character into an unquoted string.
So you could have written:
cd Let\'s\ Go\ Play\!
But the double-quoted version one seems simpler.
Exclamations points are an extension to the Posix standard (the above rules comes directly from the Posix standard), and the bash implementation is a bit quirky and sometimes really annoying. Exclamation points introduce history expansion, unless they are inside single quotes, are preceded by a backslash, or are followed by whitespace or either an equals sign or (if shell option extglob is enabled) an open parenthesis. Inside double quotes, an exclamation point is also not special just before the closing quote. (You can change the history expansion character to something other than an exclamation point so technically I should write "the history expansion character".)
Even though a backslash makes an exclamation mark unspecial, the backslash is not removed from the input stream unless it would have been removed by the Posix rules. So the exclamation point in
echo "a\!b"
is an ordinary character (it is preceded by a backslash), but the backslash is also an ordinary character (it is not followed by one of the characters in the double-quote list), so the result is
a\!b
(Although I copied those rules from the bash manual, I know there are some other cases where history expansion is suppressed, such as when the exclamation point is part of a parameter expansion such as $! or ${!name}. And I think there are more of these exceptions that I can't remember off-hand.)
I find all that so annoying, and I rely so little on history expansion, that I simply turn it off by adding set +H to my bash startup file ~/.bashrc. If you turn history expansion off, then exclamation points lose all special significance. However, there are people who seem to really like history expansion, and if you're one of them, more power to you.
With this program (cs.exe):
class Program
{
static void Main(string[] args)
{
foreach (var item in args)
{
Console.WriteLine(item);
}
}
}
And run:
> cs.exe go\to\a_path
go\to\a_path
> cs.exe "go\to\a path"
go\to\a path
> cs.exe "go\to\a path\"
go\to\a path"
> cs.exe 'go\to\a path\'
'go\to\a
path\'
That means if your path has a space so you quote it, be very careful NOT to put a trailing \ at the end, otherwise your program
might just not be able to handle it as it incorrectly contains a " at the end. Single quote is even weirder!
PowerShell exhibits a similar behavior but without the difference between single and double quotes.
How do I understand this behavior? What's the underlying rule to evaluate backslash in cmd so this can be explained consistently?
As you are not calling an internal cmd command, but calling an executable file, this behaviour is not caused by cmd but the command line argument parser routines. In windows, programs don't receive a collection/array/set of arguments, but a string with all the arguments and each program tokenizes this string to obtain each element. This is usually done by routines included by the compiler that hides this operation and exposes to the code an easier way to handle arguments.
Documentation for the C Command-Line argument parser states that
Arguments are delimited by white space, which is either a space or a tab.
A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted
string can be embedded in an argument. Note that the caret (^) is not
recognized as an escape character or delimiter.
A double quotation mark preceded by a backslash, \", is interpreted as a literal double quotation mark (").
Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
If an even number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every
pair of backslashes (\\), and the double quotation mark (") is
interpreted as a string delimiter.
If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every
pair of backslashes (\\) and the double quotation mark is interpreted
as an escape sequence by the remaining backslash, causing a literal
double quotation mark (") to be placed in argv.
There is also a set of undocumented/non official rules (How Command Line Parameters Are Parsed)
Outside a double quoted block a " starts a double quoted block.
Inside a double quoted block a " followed by a different character (not another ") ends the double quoted block.
Inside a double quoted block a " followed immediately by another " (i.e. "") causes a single " to be added to the output, and the
double quoted block continues.
The .Net argument parsing rules are just a derivation of those rules. If you need a different behaviour, then you should use the Environment.CommandLine property to retrieve the full command line string and write your own parsing code.
I want to launch a windows executable from a batch file where the path to the executable is stored in a variable.
#echo off
set qtpath=C:\Program Files\Qt\5.7\mingw53_32\bin
set execpath=%qtpath%\windeployqt.exe
echo %execpath%
%execpath% --someparams
Unfortunately executing my script throws an error:
'C:\Program' is not recognized as an internal or external command, operable program or batch file.
Looks like somehow the string gets terminated at the space in Program Files.
You should change your code to this:
#echo off
set "qtpath=C:\Program Files\Qt\5.7\mingw53_32\bin"
set "execpath=%qtpath%\windeployqt.exe"
echo "%execpath%"
"%execpath%" --someparams
The SPACE, like also TAB, ,, ;, =, VTAB (vertical tabulator, ASCII 0x0B), FF (form-feed, ASCII 0x0C) and NBSP (non-break space, ASCII 0xFF) constitute token separators in the command prompt cmd. To escape tokenisation enclose your path in between "". This avoids also trouble with special characters like ^, ( and ), &, <, > and |.
The quotation marks in the set command lines again avoid trouble with special characters; they do not become part of the variable value because they enclose the entire assignment expression. Note that this syntax requires the command extensions to be enabled, but this is the default anyway.
I recommend not to include the quotation marks into variable values (set VAR="some value"), because then you could run into problems particularly when concatenating strings due to unwanted (double-)quotation (for instance, echo "C:\%VAR%\file.txt" returns "C:\"some value"\file.txt").
You are perfectly right. If the path to the file you want to execute contains spaces, you have to surround it with quotation marks:
#echo off
set qtpath=C:\Program Files\Qt\5.7\mingw53_32\bin
set execpath="%qtpath%\windeployqt.exe"
echo %execpath%
%execpath% --someparams
This should work.
It will also work when you surround %execpath% with quotation marks:
"%execpath%" --someparams
As per this question How to input a path with a white space? I have declared a directory path like that:
startup='/cygdrive/c/Users/Me/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup'; I tried to wrap the path in to double quotes but it is not working either.
But for some reason when I am typing $startup I am getting an error:
$ $startup
bash: /cygdrive/c/Users/Alex/AppData/Roaming/Microsoft/Windows/Start: No such file or directory
How would u fix that?
Surround your variable with quotes:
$ "$startup"
You should always quote variables to be safe. You can refer to this page for more details.
As it states in the first paragraph: "When referencing a variable, it is generally advisable to enclose its name in double quotes. This prevents reinterpretation of all special characters within the quoted string -- except $, ` (backquote), and \ (escape)."
You can also refer to this page which states: The basic rule of thumb is that you should double-quote every expansion. This prevents unwanted word splitting and globbing. When in doubt, quote it.
In Unix I could run myscript '"test"' and I would get "test".
In Windows cmd I get 'test'.
How can I pass double-quotes as a parameter? I would like to know how to do this manually from a cmd window so I don't have to write a program to test my program.
Another way to escape quotes (though probably not preferable), which I've found used in certain places is to use multiple double-quotes. For the purpose of making other people's code legible, I'll explain.
Here's a set of basic rules:
When not wrapped in double-quoted groups, spaces separate parameters:program param1 param2 param 3 will pass four parameters to program.exe: param1, param2, param, and 3.
A double-quoted group ignores spaces as value separators when passing parameters to programs:program one two "three and more" will pass three parameters to program.exe: one, two, and three and more.
Now to explain some of the confusion:
Double-quoted groups that appear directly adjacent to text not wrapped with double-quotes join into one parameter:hello"to the entire"world acts as one parameter: helloto the entireworld.
Note: The previous rule does NOT imply that two double-quoted groups can appear directly adjacent to one another.
Any double-quote directly following a closing quote is treated as (or as part of) plain unwrapped text that is adjacent to the double-quoted group, but only one double-quote:"Tim says, ""Hi!""" will act as one parameter: Tim says, "Hi!"
Thus there are three different types of double-quotes: quotes that open, quotes that close, and quotes that act as plain-text.
Here's the breakdown of that last confusing line:
" open double-quote group
T inside ""s
i inside ""s
m inside ""s
inside ""s - space doesn't separate
s inside ""s
a inside ""s
y inside ""s
s inside ""s
, inside ""s
inside ""s - space doesn't separate
" close double-quoted group
" quote directly follows closer - acts as plain unwrapped text: "
H outside ""s - gets joined to previous adjacent group
i outside ""s - ...
! outside ""s - ...
" open double-quote group
" close double-quote group
" quote directly follows closer - acts as plain unwrapped text: "
Thus, the text effectively joins four groups of characters (one with nothing, however):
Tim says, is the first, wrapped to escape the spaces
"Hi! is the second, not wrapped (there are no spaces)
is the third, a double-quote group wrapping nothing
" is the fourth, the unwrapped close quote.
As you can see, the double-quote group wrapping nothing is still necessary since, without it, the following double-quote would open up a double-quoted group instead of acting as plain-text.
From this, it should be recognizable that therefore, inside and outside quotes, three double-quotes act as a plain-text unescaped double-quote:
"Tim said to him, """What's been happening lately?""""
will print Tim said to him, "What's been happening lately?" as expected. Therefore, three quotes can always be reliably used as an escape.However, in understanding it, you may note that the four quotes at the end can be reduced to a mere two since it technically is adding another unnecessary empty double-quoted group.
Here are a few examples to close it off:
program a b REM sends (a) and (b)
program """a""" REM sends ("a")
program """a b""" REM sends ("a) and (b")
program """"Hello,""" Mike said." REM sends ("Hello," Mike said.)
program ""a""b""c""d"" REM sends (abcd) since the "" groups wrap nothing
program "hello to """quotes"" REM sends (hello to "quotes")
program """"hello world"" REM sends ("hello world")
program """hello" world"" REM sends ("hello world")
program """hello "world"" REM sends ("hello) and (world")
program "hello ""world""" REM sends (hello "world")
program "hello """world"" REM sends (hello "world")
Final note: I did not read any of this from any tutorial - I came up with all of it by experimenting. Therefore, my explanation may not be true internally. Nonetheless all the examples above evaluate as given, thus validating (but not proving) my theory.
I tested this on Windows 7, 64bit using only *.exe calls with parameter passing (not *.bat, but I would suppose it works the same).
I cannot quickly reproduce the symptoms: if I try myscript '"test"' with a batch file myscript.bat containing just #echo.%1 or even #echo.%~1, I get all quotes: '"test"'
Perhaps you can try the escape character ^ like this: myscript '^"test^"'?
Try this:
myscript """test"""
"" escape to a single " in the parameter.
The 2nd document quoted by Peter Mortensen in his comment on the answer of Codesmith made things much clearer for me. That document was written by windowsinspired.com. The link repeated: A Better Way To Understand Quoting and Escaping of Windows Command Line Arguments.
Some further trial and error leads to the following guideline:
Escape every double quote " with a caret ^. If you want other characters with special meaning to the Windows command shell (e.g., <, >, |, &) to be interpreted as regular characters instead, then escape them with a caret, too.
If you want your program foo to receive the command line text "a\"b c" > d and redirect its output to file out.txt, then start your program as follows from the Windows command shell:
foo ^"a\^"b c^" ^> d > out.txt
If foo interprets \" as a literal double quote and expects unescaped double quotes to delimit arguments that include whitespace, then foo interprets the command as specifying one argument a"b c, one argument >, and one argument d.
If instead foo interprets a doubled double quote "" as a literal double quote, then start your program as
foo ^"a^"^"b c^" ^> d > out.txt
The key insight from the quoted document is that, to the Windows command shell, an unescaped double quote triggers switching between two possible states.
Some further trial and error implies that in the initial state, redirection (to a file or pipe) is recognized and a caret ^ escapes a double quote and the caret is removed from the input. In the other state, redirection is not recognized and a caret does not escape a double quote and isn't removed. Let's refer to these states as 'outside' and 'inside', respectively.
If you want to redirect the output of your command, then the command shell must be in the outside state when it reaches the redirection, so there must be an even number of unescaped (by caret) double quotes preceding the redirection. foo "a\"b " > out.txt won't work -- the command shell passes the entire "a\"b " > out.txt to foo as its combined command line arguments, instead of passing only "a\"b " and redirecting the output to out.txt.
foo "a\^"b " > out.txt won't work, either, because the caret ^ is encountered in the inside state where it is an ordinary character and not an escape character, so "a\^"b " > out.txt gets passed to foo.
The only way that (hopefully) always works is to keep the command shell always in the outside state, because then redirection works.
If you don't need redirection (or other characters with special meaning to the command shell), then you can do without the carets. If foo interprets \" as a literal double quote, then you can call it as
foo "a\"b c"
Then foo receives "a\"b c" as its combined arguments text and can interpret it as a single argument equal to a"b c.
Now -- finally -- to the original question. myscript '"test"' called from the Windows command shell passes '"test"' to myscript. Apparently myscript interprets the single and double quotes as argument delimiters and removes them. You need to figure out what myscript accepts as a literal double quote and then specify that in your command, using ^ to escape any characters that have special meaning to the Windows command shell. Given that myscript is also available on Unix, perhaps \" does the trick. Try
myscript \^"test\^"
or, if you don't need redirection,
myscript \"test\"
I'm calling powershell from cmd, and passing quotes and neither escapes here worked. The grave accent worked to escape double quotes on this Win 10 surface pro.
>powershell.exe "echo la`"" >> test
>type test
la"
Below are outputs I got for other characters to escape a double quote:
la\
la^
la
la~
Using another quote to escape a quote resulted in no quotes.
As you can see, the characters themselves got typed, but didn't escape the double quotes.
Maybe you came here, because you wonder how to escape quotes that you need in the command that you pass to /c on cmd.exe? Well you don't:
CMD /c "MKDIR "foo bar""
will execute
MKDIR "foo bar"
which is really a behavior that I did not expect in the first glance.