简体   繁体   中英

How to pass escaped double quote to batch file

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:

  1. 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.

  2. 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:""="%

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM