how to pass a parameter with space or ; to function?
call :MyFunct "arg1" "arg2 arg2";"arg2"
:MyFunct
echo %~2
I would like to retrieve from %~1 "arg2 arg2";"arg2" but do not know how to do
For your sample "arg1" "arg2 arg2";"arg2" the arguments are
arg1="arg1"
arg2="arg2 arg2"
arg3="arg2"
That's simply the rule of cmd.exe, any unquoted delimiter in the arguments splits arguments, delimiters are <space>;,=
If you want a different behavior, you need to write your own parsing function on the basis of %* or even better on the bullet proof argument reading
Related
In python, you can evaluate strings like this:
eval("true")
which returns a boolean set to True
Is there a way to pass an entire command into a batch script argument like this:
my_script.bat "my_command -do_x=5 do_y=56 ...etc"
Then have the batch script set that argument in the quotes to a variable:
set execute_script=%1
And finally run it? In python we would do:
eval(execute_script)
How can I do this in batch script?
set "execute_script=%1"
%execute_script%
probably.
The eval function in python is very useful indeed, but it has signatures that defines the eval function to perform actual evaluations dynamically. That is sadly not something cmd has by default. What we can do is to evaluate if a variable is defined, which is not of much use comapred to eval.
So creating a variable, evaluating that it is defined then executing it as a macro:
#echo off
set "string=%*"
if defined string %string%
but that is useless if you simplify it by not creating macros:
if not "%1" == "" %*
Please consider the following very simple batch script (the file is named test.cmd):
#echo off
set "var1=%~1"
echo %var1%
The script should be called with one command line parameter, should assign the string which is contained in that parameter to a variable, and should output the variable.
As expected, I get an error message when I call this script with a command line parameter which contains an ampersand (&):
C:\Batch>test "a&b"
a
'b' is not recognized as an internal or external command,
operable program or batch file.
The reason for this has been discussed in some other questions here and elsewhere, for example that one; the usual remedy is to use delayed expansion. So I changed the script accordingly:
#echo off
setLocal enableDelayedExpansion
set "var1=%~1"
echo !var1!
Now it works with the parameter from before:
C:\Batch>test "a&b"
a&b
But there is a new problem. When the command line parameter contains an exclamation mark (!), it will be dropped from the output:
C:\Batch>test a!b
ab
This behavior also has been discussed at several places, for example here; the crucial thing to note is that dropping the exclamation mark happens during the assignment, not during the echo.
Despite a lot of research, I did not find a question here which provided an elegant solution for both problems at once. That is, is there an elegant way to assign a command line parameter to a variable when that parameter contains an ampersand AND an exclamation mark?
It seems that I need the delayed expansion to treat the ampersand correctly, but this destroys the exclamation mark.
The only solution I currently see is to not use delayed expansion and to add code to explicitly quote all ampersands in the input string. This would be so ugly that I seriously think that I am missing something here.
As a side note, the reason for the problem actually seems to be that there (IMHO!) is no way to get the command line parameter in a delayed-expanded fashion. The syntax for the first parameter is %~1, there is no such thing as !~1.
Move the setLocal enableDelayedExpansion after the the set„ that's all.
#echo off
set "var1=%~1"
setLocal enableDelayedExpansion
echo !var1!
I'm trying to remove incoming quotes for a doskey macro that will let me use "export" as "set". Here's what I have:
doskey export=set $*
Except when I run with the following:
export VAR="value"
I end up with:
VAR="value"
vs what I wanted:
VAR=value
I think I have to write a little method of sorts to 'clean' the input to set but I don't know how to do that - something like "for (var1=var2) do set var1=~var2", but I can't get anything like that to work.
Help!
You can probably do it with a for loop too, but this is easier:
set ORIGARGS=%*
set ARGCOPY=
:copyargs
set "ARGCOPY=%ARGCOPY% %~1"
shift
if not [%1]==[] goto:copyargs
ie. (line-by-line)
save the original %* since we're going to destroy it.
prepare a variable (ARGCOPY) to put the converted arguments into
label (target of goto in line 6)
append the first argument %1 to ARGCOPY, but remove quotes (%~1)
shift all arguments to the left one space (i.e. what was %2 becomes %1, etc.)
if we've reached the end of the arguments then %1 has no value, otherwise goto line 3, where the :copyargs label is located.
when you're done %ARGCOPY% will contain the parameters without quotes.
I know there were similar questions, but there is one thing I can't find in the answers. I'm trying to pass the following string to batch file:
hello " world
This is a single argument. Here is my batch file:
#echo off
#echo %1
Now if I run it from command line, I'm getting the following results:
>C:\file.bat "hello "" world"
"hello "" world"
>C:\file.bat "hello \" world"
"hello \"
>C:\file.bat "hello """ world"
"hello """
In all cases I'm getting the wrong result, how do I escape a double quote and pass it correctly? Or should I do any additional conversion steps in the batch file itself?
It is impossible to pass a string literal value of hello " world as a batch parameter for two reasons:
Space cannot be escaped with regard to parameter tokenization. Parameters are always delimited by unquoted token delimiters, even if they are preceded by the ^ escape character. The token parameter token delimiters are {space}, {tab}, ,, ; =, and {0xFF}. The only way to include a token delimiter as part of a parameter is to make sure the delimiter is quoted.
It is impossible to escape a quote within a quoted string. Quotes are a state machine: The first encountered quote turns on quote semantics, and the subsequent one turns it off. The next quote turns it back on again, etc. If quoting is off, then a quote literal can be escaped as ^" to keep quoting off. But once quoting has begun, then there is no way to escape a closing
quote: The next quote always turns quoting off.
So no matter how you add quotes and/or escaped quotes, there will always be an unquoted space, thus the string will be treated as two parameters.
You could adopt the strategy recommended by Hapax - Quote the entire string, and double any quote literals within the string: "Hello "" world".
However I would make a slight change and use %~1 instead of %1 so as to remove the outer quotes. Then the doubled quotes should be converted back to a single quote:
#echo off
set "arg1=%~1"
set "arg1=%arg1:""="%"
echo %arg1%
But there are other potential issues with passing string literals as batch parameters. The most insidious is caret doubling. It is impossible to pass a quoted caret as a parameter if the caller uses CALL. I won't get into the mechanism behind the problem. See https://stackoverflow.com/a/4095133/1012053 if you want more information. But the following illustrates the problem:
test.bat
#echo %1
-- Sample cmd session --
D:\test>test "^"
"^"
D:\test>call test "^"
"^^"
Because of the many complications with passing string literals as batch parameters, the most effective strategy used in advanced batch scripting is to store the value in an environment variable, and then pass the variable name as the parameter. The batch script can then use delayed expansion to get the correct value:
test2.bat
#echo off
setlocal enableDelayedExpansion
set "arg1=!%1!"
echo !arg1!
-- Sample cmd session --
D:\test>set "myVar=Hello world! ^&|<>" How are you doing? !^^^&^|^<^>^"
D:\test>set myVar
myVar=Hello world! ^&|<>" How are you doing? !^&|<>
D:\test>test2 myVar
Hello world! ^&|<>" How are you doing? !^&|<>
D:\test>call test2 myVar
Hello world! ^&|<>" How are you doing? !^&|<>
The way to keep quotes is to pass them doubled. However, this passes both of them.
You can then process the input and remove the doubles.
Executing using file.bat "hello "" world", we use:
#echo off
set param=%1
set param=%param:""="%
echo %param%
(result: "hello " world")
A shorter version:
#echo off
set param=%1
echo %param:""="%
I'm trying to remove quotes in some text using parameter expansion in Batch. Can anyone tell me why this:
#echo off
setlocal
set args=%*
echo %args:"=%
prints "= instead of nothing? As far as I can see %args:"=% should replace all quotes with nothing, so I don't get why this is happening.
Any help would be appreciated, thanks!
edit: To clarify, I'm not passing any parameters to the batch script.
That is the result you get when you do not pass any arguments to your script.
If args is not defined, then %args:"=% is expanded as follows:
%args: is treated as a non existent variable expansion, which becomes nothing
"= is treated as itself
% (a lone percent) is stripped
It is not intuitive, but that happens to be how cmd.exe works. See https://stackoverflow.com/a/7970912/1012053 for more info.
You can prevent the problem by using if defined
#echo off
setlocal
set args=%*
if defined args echo %args:"=%
It works here
C:\Windows\system32>"C:\Users\User\Desktop\Test2.bat" dog
dog
Removing echo off shows this
C:\Windows\system32>setlocal
C:\Windows\system32>set args=dog
C:\Windows\system32>echo dog
dog
You are not passing any command line arguments.
C:\Windows\system32>"C:\Users\User\Desktop\Test2.bat"
C:\Windows\system32>setlocal
C:\Windows\system32>set args=
C:\Windows\system32>echo "=
"=