Sample batch execution:
test.bat /s v1.1 1,3,4,5
I want to split the parameter into three tokens using space as a delimiter. The result should be:
1st token = /s
2nd token = /v1.1
3rd token = 1,3,4,5
Then the 3rd token will be split again using comma as a delimiter
The code below splits the arguments using common delimiters such as space, comma, etc.
#ECHO OFF
SET PARAMS=
:_PARAMS_LOOP
SET PARAMS=%PARAMS%%1
ECHO %1
SHIFT
IF NOT "%1"=="" GOTO _PARAMS_LOOP
Execution:
test.bat /s v4.1 1,2,3,4
Result:
/s
v4.1
1
3
4
5
I just want to use space as a delimiter, then in the 3rd token(1,3,4,5) I will split it again using comma as a delimiter and echo each of it.
The issue is that cmd recognizes a space, tab, comma, semicolon, or equals sign as command line delimiters unless they are wrapped in doublequotes.
Delimiters
Some characters in the command line are ignored by batch files,
depending on the DOS version, wether they are "escaped" or not, and
often depending on their location in the command line:
commas (",") are replaced by spaces, unless they are part of a string
in doublequotes
semicolons (";") are replaced by spaces, unless they
are part of a string in doublequotes
"=" characters are sometimes
replaced by spaces, not if they are part of a string in doublequotes
the first forward slash ("/") is replaced by a space only if it
immediately follows the command, without a leading space
multiple spaces are replaced by a single space, unless they are part of a
string in doublequotes
tabs are replaced by a single space
leading spaces before the first command line argument are ignored
I know of several occasions where these seemingly useless "features" proved very
handy. Keep in mind, though, that these "features" may vary with the
operating systems used.
More on command line parsing can be found on the PATH and FOR
(especially FOR's interactive examples) pages.
http://www.robvanderwoude.com/parameters.php
Related
I have a batch variable called version with this value "2930.2323 "
Now i want to remove the last character (or all spaces). I've tried both ways but the whitespace is not removed.
// MYVAR is set at the beginning of my batch file by another source code
SET "MYVAR=%MYVAR: =%"
Your code doesn't remove "Whitespaces", but SPACEs only (ie if it's a TAB it won't be removed unless you add another line to remove TABs too).
For your given string, I suggest another approach:
for %%a in (%myvar%) do set "myvar=%%a"
echo --%myvar%--
Note: that only works for whitespaces at the beginning or end of the string. A space in the middle of the string will split the string into two (or more). Also, some special characters will be problematic. But it will work with strings like your example ("Version numbers")
Sub-string expansion works within the set of a for loop (that is the parenthesised part after in) when immediate expansion is used (write %%I instead of %I in a batch file):
set "X=123"
for %I in (%X:~1,1%) do #echo %I
However, it fails when delayed expansion is applied:
for %I in (!X:~1,1!) do #echo %I
I would expect the output to be:
2
But instead it is:
!X:~1
1!
Why is this and how can I prevent that?
I know I could work around that by quoting the set and using ~, but this is not what I want here:
for %I in ("!X:~1,1!") do #echo %~I
The following command line fails too:
for %I in (!X:*2=!) do #echo %I
The unexpected output is:
!
Also for command lines using the /R, /L and /R switches fail with such sub-string syntax.
It surely has got something to do with the fact that , and = are token separators for cmd, just like SPACE, TAB, ;, etc.
According to the thread How does the Windows Command Interpreter (CMD.EXE) parse scripts? and also numerous comments here, the answer lies in the special way for loops are parsed.
The key is the following excerpt of this answer (see the italic text in particular):
Phase 2) Process special characters, tokenize, and build a cached command block:
[...]
Three commands get special handling - IF, FOR, and REM
[...]
FOR is split in two after the DO. A syntax error in the FOR construction will result in a fatal syntax error.
The portion through DO is the actual FOR iteration command that flows all the way through phase 7
All FOR options are fully parsed in phase 2.
The IN parenthesized clause treats <LF> as <space>. After the IN clause is parsed, all tokens are concatenated together to form a single token.
Consecutive token delimiters collapse into a single space throughout the FOR command through DO.
Due to the fact that delayed expansion happens after parsing of for and the described behaviour, token separators like SPACE, TAB, ,, ;, =, etc. become converted to a single SPACE, hence a sub-string expansion expression like !X:~1,1! is changed to !X:~1 1!, and a sub-string substitution expression like !X:*2=! is changed to !X:*2 !, which both are invalid syntax.
Therefore to solve the issue you need to escape the token separators by ^ like:
for %I in (!X:~1^,1!) do #echo %I
and:
for %I in (!X:*2^=!) do #echo %I
(By the way, there is a very similar problem with if statements.)
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.
I have a variable that I need to check if it contains spaces, and exit if it does.
I have this code:
if not [%VAR%]==[%VAR: =%] exit 1
.. but it does not work for spaces. I can use it for other characters though. For example looking for "/" works with same code:
if not [%VAR%]==[%VAR:/=%] exit 1
Is there a way to do it?
Thanks,
This should do as you need: double quotes are always the solution for spaces, and also with some other characters.
if not "%VAR%"=="%VAR: =%" exit 1
While the answer from foxidrive will handle the problem for simple cases and is the obvious answer (and yes, this is what i usually use), it will fail for values with a quote inside
"If needed" this should handle the marginal cases
for /f "tokens=2 delims= " %%a in (".%var:"=%.") do exit 1
The "trick" is to enclose the value with removed quotes and tokenize the string using for command. To avoid spaces at the start and end of the string from being removed a pair of aditional dots are included. If the string do not include a space, it will only have one token. But the for command is requesting the second token, so the code inside will not be executed for strings without a space in them.
I have a string like this:
Testing:"abc"def"ghi"
I want to get: abc"def"ghi and put it into a variable, is there any possible way?
I want a general way of doing that (first and last quotes, not first and fourth quotes)
This will work reliably as long as the string does not contain unquoted special characters like & | > < ^
#echo off
set str=Testing:"abc"def"ghi"extra
echo str = %str%
set "new=%str:*"=%
echo new = %new%
-- OUTPUT --
str = Testing:"abc"def"ghi"extra
new = abc"def"ghi
Explanation
There are two parts to this solution, both in the same line of code.
1) Remove all characters up through the first ".
This part uses the documented search and replace feature of variable expansion, with an asterisk before the search string. The following is an excerpt from the help gotten by typing HELP SET or SET /? from the command prompt.
Environment variable substitution has been enhanced as follows:
%PATH:str1=str2%
would expand the PATH environment variable, substituting each occurrence
of "str1" in the expanded result with "str2". "str2" can be the empty
string to effectively delete all occurrences of "str1" from the expanded
output. "str1" can begin with an asterisk, in which case it will match
everything from the beginning of the expanded output to the first
occurrence of the remaining portion of str1.
2) Find the last occurrence of " and truncate the string at that point.
The entire SET assignment expression can be enclosed in quotes, and the enclosing quotes will be discarded and all text after the last quote ignored. The statement below will define variable var to have a value of value.
set "var=value" this text after the last quote is ignored
If there is no last quote, then the entire remainder of the line is included in the value, possibly with hidden spaces.
set "var=This entire sentence is included in the value.
I am not aware of any official documentation for this feature, but it is an important tool for batch file development.
This process occurs after the expansion from part 1 has completed. So the the SET truncates at the last occurrence of " in the expanded value.