如何从 Windows 批处理文件中的 ECHO 字符串中去除引号?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/804646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:18:35  来源:igfitidea点击:

How do you strip quotes out of an ECHO'ed string in a Windows batch file?

windowsbatch-filesedquotesecho

提问by Lance Roberts

I have a Windows batch file I'm creating, but I have to ECHO a large complex string, so I'm having to put double quotes on either end. The problem is that the quotes are also being ECHOed to the file I'm writing it to. How do you ECHO a string like that and strip the quotes off?

我有一个正在创建的 Windows 批处理文件,但我必须回显一个大的复杂字符串,所以我必须在两端加上双引号。问题是引号也被回显到我正在写入的文件中。你如何回显这样的字符串并去掉引号?

UPDATE:

更新:

I've spent the last two days working on this and finally was able to kludge something together. Richard's answer worked to strip the quotes, but even when I put the ECHO in the subroutine and directly outputted the string, Windows still got hung up on the chars in the string. I'll accept Richard's answer since it answers the question asked.

过去两天我一直在研究这个,终于能够把一些东西拼凑起来。理查德的回答可以去除引号,但是即使我将 ECHO 放在子例程中并直接输出字符串,Windows 仍然挂在字符串中的字符上。我会接受理查德的回答,因为它回答了提出的问题。

I ended up using Greg's sed solution, but had to modify it because of sed/windows bugs/features (it didn't help that it came with no documentation). There are a few caveats to using sed in Windows: you have to use double quotes instead of single quotes, you can't escape the double quotes in the string directly, you have to endquote the string, escape using the ^ (so ^") then beqin quote for the next section. Also, someone pointed out that if you pipe input to sed, there's a bug with a pipe being in the string (I didn't get to verify this since in my final solution, I just found a way not to have all quotes in the middle of the string, and just removed all quotes, I never could get the endquote to be removed by itself.) Thanks for all the help.

我最终使用了 Greg 的 sed 解决方案,但由于 sed/windows 错误/功能而不得不对其进行修改(它没有提供任何文档并没有帮助)。在 Windows 中使用 sed 有一些注意事项:你必须使用双引号而不是单引号,你不能直接转义字符串中的双引号,你必须结束引用字符串,使用 ^ 转义(所以 ^" ) 然后是下一部分的 beqin 引用。另外,有人指出,如果您将输入通过管道传输到 sed,则字符串中存在管道的错误(我没有验证这一点,因为在我的最终解决方案中,我刚刚发现一种不在字符串中间包含所有引号的方法,只是删除了所有引号,我永远无法自行删除 endquote。)感谢所有帮助。

回答by Richard A

The call command has this functionality built in. To quote the help for call:

call 命令内置了此功能。引用 call 的帮助:

 Substitution of batch parameters (%n) has been enhanced.  You can
 now use the following optional syntax:

 %~1         - expands %1 removing any surrounding quotes (")

Here is a primitive example:

这是一个原始示例:

@echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof

:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof

Output:

输出:

C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text

I should credit the 'environment variable tunneling' technique (endlocal&set ret=%thestring%) to Tim Hill, 'Windows NT Shell Scripting'. This is the only book I have ever found that addresses batch files with any depth.

我应该将“环境变量隧道”技术 (endlocal&set ret=%thestring%) 归功于 Tim Hill,“Windows NT Shell Scripting”。这是我发现的唯一一本书,可以解决任何深度的批处理文件。

回答by Daniel Budzyński

The following approach can be used to print a string without quotes:

以下方法可用于打印不带引号的字符串:

echo|set /p="<h1>Hello</h1>"

pushing this string into file:

将此字符串推送到文件中:

echo|set /p="<h1>Hello</h1>" > test.txt

To check:

去检查:

type test.txt

回答by Big Joe

You can use the %var:x=y%construction that replaces all xwith y.

您可以使用%var:x=y%替换所有施工xy

See this example what it can do:

看看这个例子它可以做什么:

set I="Text in quotes"
rem next line replaces " with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without' 
echo stripped %J:in=without%

回答by Explorer09

To remove all quotation marks from a set variable, you need Delayed Variable Expansion to securely expand the variable and process it. Expansion using percent signs (i.e. %VAR%and %1) are inherently unsafe (they are vulnerable to command injection; read this for details).

要从设置的变量中删除所有引号,您需要延迟变量扩展来安全地扩展变量并对其进行处理。使用百分号(即%VAR%%1)进行扩展本质上是不安全的(它们容易受到命令注入的影响;阅读此了解详细信息)。

SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.

To strip quotes from a text file or a command output, things will get complicated because with Delayed Expansion, string like !VAR!within the text document will get expanded (within the %%iexpansion in FOR /F) when it shouldn't. (This is another vulnerability—information disclosure—that's not documented elsewhere.)

要从文本文件或命令输出中去除引号,事情会变得复杂,因为使用延迟扩展,!VAR!文本文档中的字符串将%%iFOR /F不应该扩展时扩展(在 中的扩展内)。(这是另一个漏洞——信息泄露——其他地方没有记录。)

To safely parse the document, a switch between delayed-expansion-enabled and -disabled environment is needed.

为了安全地解析文档,需要在启用延迟扩展和禁用延迟扩展的环境之间进行切换。

REM Suppose we fetch the text from text.txt

SETLOCAL DisableDelayedExpansion
REM The FOR options here employs a trick to disable both "delims"
REM characters (i.e. field separators) and "eol" character (i.e. comment
REM character).
FOR /F delims^=^ eol^= %%L IN (text.txt) DO (

    REM This expansion is safe because cmd.exe expands %%L after quotes
    REM parsing as long as DelayedExpansion is Disabled. Even when %%L
    REM can contain quotes, carets and exclamation marks.
    SET "line=%%L"

    CALL :strip_quotes
    REM Print out the result. (We can't use !line! here without delayed
    REM expansion, so do so in a subroutine.)
    CALL :print_line
)
ENDLOCAL
GOTO :EOF

REM Reads !line! variable and strips quotes from it.
:strip_quotes
    SETLOCAL EnableDelayedExpansion
    SET line=!line:^"=!

    REM Make the variable out of SETLOCAL
    REM I'm expecting you know how this works:
    REM (You may use ampersand instead:
    REM `ENDLOCAL & SET "line=%line%"`
    REM I just present another way that works.)
    (
    ENDLOCAL
    SET "line=%line%"
    )
GOTO :EOF

:print_line
    SETLOCAL EnableDelayedExpansion
    ECHO !line!
    ENDLOCAL
GOTO :EOF

The delims^=^ eol^=in the code above probably needs explanation: This effectively disables both "delims" characters (i.e. field separators) and "eol" character (i.e. comment character). Without it, the "delims" will default to tab and space and "eol" defaults to a semicolon.

delims^=^ eol^=上面的代码可能需要解释:这将有效地禁用这两个“delims”字符(即场分隔符)和“EOL”字符(即注释字符)。没有它,“delims”将默认为制表符和空格,而“eol”默认为分号。

  • The eol=token always read whichever the next character it is after the equal sign. To disable it this token has to be in the end of the options string so that no character may be used for "eol", effectively disabling it. If the options string is quoted, it might use quotation mark (") as the "eol", so we must not quote the options string.
  • The delims=option, when it's not the last option in the options string, will be terminated by a space. (To include space in "delims" it has to be the last option of FOR /Foptions.) So delims=followed by a space and then another option disables the "delims".
  • eol=令牌总是读取其下一个字符是等号后面。要禁用它,此标记必须位于选项字符串的末尾,以便“eol”不能使用任何字符,从而有效地禁用它。如果选项字符串被引用,它可能会使用引号 (") 作为 "eol",所以我们不能引用选项字符串。
  • delims=选项,当它不是在选项字符串中的最后一个选项,将用空格终止。(要在“delims”中包含空格,它必须是选项的最后一个选项FOR /F。)所以delims=后跟一个空格,然后另一个选项禁用“delims”。

回答by cyber_by

I know that it is not actually for the author, but if you need to send some text to the file without quotes - the solution below works for me. You do not need to use quotes in the echo command, just surround the complete command with brackets.

我知道它实际上并不适合作者,但是如果您需要将一些文本发送到不带引号的文件中 - 下面的解决方案对我有用。您不需要在 echo 命令中使用引号,只需将完整的命令用括号括起来即可。

(
    echo first very long line
    echo second very long line with %lots% %of% %values%
) >"%filename%"

回答by Andrew_M_Garland

The following batch file starts a series of programs with a delay after each one.

以下批处理文件启动一系列程序,每个程序都有延迟。

The problem is to pass a command line with parameters for each program. This requires quotes around the program argument, which are removed when the call is made. This illustrates a few techniques in batch file processing.

问题是为每个程序传递一个带有参数的命令行。这需要程序参数周围的引号,在进行调用时将其删除。这说明了批处理文件处理中的一些技术。

Look in the local subroutine :mystart for how an argument in quotes is passed in, and the quotes are removed.

查看本地子例程 :mystart 以了解如何传入引号中的参数,并删除引号。

@echo off

rem http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/if.mspx?mfr=true

rem Start programs with delay

rem  Wait n seconds
rem  n number retries to communicate with the IP address
rem  1000 milliseconds between the retries
rem  127.0.0.1 is the LocalHost
rem  start /b (silent)  /min (minimized) /belownormal (lower priority)
rem  /normal provides a no-op switch to hold the place of argument 1

rem  start  /normal "Opinions"  %SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion
rem  ping 127.0.0.1 -n 8 -w 1000 > nul

rem   Remove quotes in Batch
rem     http://ss64.com/nt/syntax-dequote.html
rem   String manipulation in Batch
rem     http://www.dostips.com/DtTipsStringManipulation.php
rem   ^ line continuation
rem   
rem   set p="One Two"      p has the exact value  "One Two" including the quotes           
rem   set p=%p:~1,-1%      Removes the first and last characters
rem   set p=%p:"=%         Removes all double-quotes
rem   set p=%p:cat=mouse%  Replaces cat with mouse

rem  ping 127.0.0.1 -n 12 -w 1000 > nul
rem        1       2            3                                                         4

@echo on
call :mystart /b/min  "Opinions"   "%SystemRoot%\explorer.exe  /e,d:\agar\jobs\opinion"   8  
@echo on
call :mystart /b/min  "Notepad++"  D:\Prog_D\Notepad++\notepad++.exe  14
@echo on
call :mystart /normal "Firefox"    D:\Prog_D\Firefox\firefox.exe      20
@rem call :mystart /b/min "ProcessExplorer"  D:\Prog_D\AntiVirus\SysInternals\procexp.exe  8
@echo on
call :mystart /b/min/belownormal "Outlook" D:\Prog_D\MSOffice\OFFICE11\outlook.exe  2
@echo off
goto:eof

:mystart
@echo off
 rem  %3 is "program-path  arguments" with the quotes. We remove the quotes
 rem  %4 is seconds to wait after starting that program
 set p=%3
 set p=%p:"=%
 start  %1  %2  %p% 
 ping 127.0.0.1 -n %4 -w 1000 > nul
 goto:eof

回答by JRL

This will turn "C:\Program Files\somefile.txt"into C:\Program Files\somefile.txtwhile still preserving cases such as Height=5'6"and Symbols="!@#

这将"C:\Program Files\somefile.txt"变成C:\Program Files\somefile.txt同时仍然保留诸如Height=5'6"Symbols="!@#

:DeQuote

SET _DeQuoteVar=%1
CALL SET _DeQuoteString=%%!_DeQuoteVar!%%
IF [!_DeQuoteString:~0^,1!]==[^"] (
IF [!_DeQuoteString:~-1!]==[^"] (
SET _DeQuoteString=!_DeQuoteString:~1,-1!
) ELSE (GOTO :EOF)
) ELSE (GOTO :EOF)
SET !_DeQuoteVar!=!_DeQuoteString!
SET _DeQuoteVar=
SET _DeQuoteString=
GOTO :EOF

Example

例子

SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%

回答by james

The above answer (starting with :DeQuote) assumes delayed environment variable expansion is set to on. From cmd /?:

上述答案(以 :DeQuote 开头)假定延迟环境变量扩展设置为开启。从 cmd /?:

Delayed environment variable expansion is NOT enabled by default. You can enable or disable delayed environment variable expansion for a particular invocation of CMD.EXE with the /V:ON or /V:OFF switch. You can enable or disable completion for all invocations of CMD.EXE on a machine and/or user logon session by setting either or both of the following REG_DWORD values in the registry using REGEDT32.EXE:

默认情况下不启用延迟环境变量扩展。您可以使用 /V:ON 或 /V:OFF 开关为 CMD.EXE 的特定调用启用或禁用延迟环境变量扩展。通过使用 REGEDT32.EXE 在注册表中设置以下任一或两个 REG_DWORD 值,您可以为计算机和/或用户登录会话上的所有 CMD.EXE 调用启用或禁用完成:

HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion

    and/or

HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion

to either 0x1 or 0x0. The user specific setting takes precedence over the machine setting. The command line switches take precedence over the registry settings.

到 0x1 或 0x0。用户特定设置优先于机器设置。命令行开关优先于注册表设置。

If delayed environment variable expansion is enabled, then the exclamation character can be used to substitute the value of an environment variable at execution time.

如果启用了延迟环境变量扩展,则可以在执行时使用感叹号来替换环境变量的值。

回答by TwoByteHero

Using the FOR command to strip the surrounding quotation marks is the most efficient way I've found to do this. In the compact form (Example 2) it's a one-liner.

使用 FOR 命令去除周围的引号是我发现的最有效的方法。在紧凑形式(示例 2)中,它是一个单线。

Example 1: The 5-line (commented) solution.

示例 1:5 行(注释)解决方案。

REM Set your string
SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

REM Echo your string into the FOR loop
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO (
    REM Use the "~" syntax modifier to strip the surrounding quotation marks
    ECHO %%~A
)

Example 2: The 1-liner real-world example.

示例 2:1-liner 真实世界示例。

SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO @ECHO %%~A

I find it interesting that the inner echo ignores the redirection characters '<' and '>'.
If you execute ECHO asdfsd>asdfasdyou will write file out instead of std out.

我发现有趣的是内部回声忽略了重定向字符“<”和“>”。
如果您执行,ECHO asdfsd>asdfasd您将写出文件而不是标准输出。

Hope this helps :)

希望这可以帮助 :)

Edit:

编辑:

I thought about it and realized there is an even easier (and less hacky) way of accomplishing the same thing. Use the enhanced variable substitution/expansion (see HELP SET) like this:

我想了想,意识到有一种更简单(更简单)的方法来完成同样的事情。HELP SET像这样使用增强的变量替换/扩展(请参阅 参考资料):

SET STR=" <output file>    (Optional) If specified this is the name of your edited file"

ECHO %STR:~1,-1%

That will print all but the first and last characters (your quotation marks). I would recommend using SETLOCAL ENABLEDELAYEDEXPANSIONtoo. If you need to figure out where quotation marks are located in the string you can use FINDSTR to get the character #s.

这将打印除第一个和最后一个字符(您的引号)之外的所有字符。我也会推荐使用SETLOCAL ENABLEDELAYEDEXPANSION。如果您需要找出引号在字符串中的位置,您可以使用 FINDSTR 来获取字符 #s。

回答by YDY

Daniel Budzyński's response is brilliant. It works even in situations where there are special characters in the output. For example:

Daniel Budzyński 的回答非常精彩。即使在输出中有特殊字符的情况下它也能工作。例如:

C:\> for /f "usebackq tokens=2 delims=:" %i in (`%comspec%\..\ping -n 1 -w 200 10.200.1.1 ^| \
     findstr /c:"TTL="`) do echo|set /p="%i"

bytes=32 time<1ms TTL=255

If you try tried a simple echo without the quotes, you get a error, due to the "<" in the variable:

如果您尝试不带引号的简单回显,则会由于变量中的“<”而出现错误:

C:\> set "output=bytes=32 time<1ms TTL=255"
C:\> echo %output%
The system cannot find the file specified.

C:\> echo|set /p="%output%"
bytes=32 time<1ms TTL=255