我有一个我正在创建的Windows批处理文件,但我必须ECHO一个大的复杂字符串,所以我不得不在两端加双引号。问题是引号也正在被我正在写入的文件进行ECHO。你如何ECHO这样的字符串并删除引号?
更新
我花了最后两天的时间来研究这个问题,最后能够将这些东西融合在一起。理查德的回答是剥离引号,但即使我把ECHO放在子程序中并直接输出字符串,Windows仍然挂在字符串中的字符上。我会接受理查德的回答,因为它回答了问题。
我最终使用了Greg的sed解决方案,但由于sed / windows错误/功能而不得不修改它(它没有帮助它没有文档)。在Windows中使用sed有一些注意事项:你必须使用双引号而不是单引号,你不能直接转义字符串中的双引号,你必须结束字符串,使用^进行转义(所以^“然后,有人指出,如果你把输入管道传输到sed,那么管道中就会出现一个错误(我在最后的解决方案中没有得到验证,我刚发现一种不在字符串中间包含所有引号的方法,只是删除了所有引号,我永远无法将endquote自行删除。)感谢所有帮助。
答案 0 :(得分:54)
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 (")
这是一个原始的例子:
@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
输出:
C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text
我应该将'环境变量隧道'技术(endlocal& set ret =%thestring%)归功于Tim Hill,'Windows NT Shell Scripting'。这是我发现的唯一能够解决任何深度批处理文件的书。
答案 1 :(得分:10)
您可以使用%var:x=y%
结构替换所有x
和y
。
请参阅此示例它可以执行的操作:
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%
答案 2 :(得分:7)
以下方法可用于打印不带引号的字符串:
echo|set /p="<h1>Hello</h1>"
答案 3 :(得分:3)
要从设置变量中删除所有引号,您需要延迟变量扩展来安全地扩展变量并对其进行处理。使用百分号(即%VAR%
和%1
)扩展本质上是不安全的(它们易受命令注入攻击; read this for details)。
SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.
要从文本文件或命令输出中删除引号,事情会变得复杂,因为使用延迟扩展,文本文档中的!VAR!
字符串将被扩展(在%%i
扩展中FOR /F
1}})什么时候不应该。 (这是另一个漏洞信息披露 - 其他地方没有记录。)
要安全地解析文档,需要在启用延迟扩展和禁用环境之间切换。
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
上面代码中的delims^=^ eol^=
可能需要解释:
这有效地禁用了&#34; delims&#34;字符(即字段分隔符)和&#34; eol&#34;字符(即评论字符)。没有它,&#34; delims&#34;将默认为制表符和空格和&#34; eol&#34;默认为分号。
eol=
令牌始终读取等号后面的下一个字符。要禁用它,此标记必须位于选项字符串的末尾,以便不会将任何字符用于&#34; eol&#34;,从而有效地禁用它。如果引用了选项字符串,它可能使用引号(&#34;)作为&#34; eol&#34;,因此我们不能引用选项字符串。delims=
选项,如果它不是选项字符串中的最后一个选项,将以空格终止。 (要将空格包含在&#34; delims&#34;它必须是FOR /F
选项的最后一个选项。)所以delims=
后跟一个空格然后另一个选项会禁用&#34; delims& #34; 答案 4 :(得分:2)
这会将"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
实施例
SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%
答案 5 :(得分:2)
上述答案(以:DeQuote开头)假定延迟环境变量扩展设置为开启。从cmd /?:
默认情况下,未启用延迟环境变量扩展。您 可以启用或禁用延迟环境变量扩展 使用/ V:ON或/ V:OFF开关特别调用CMD.EXE。您 可以启用或禁用对a的所有CMD.EXE调用的完成 机器和/或用户登录会话通过设置其中一个或两个 使用REGEDT32.EXE注册表中的REG_DWORD值:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion
and/or
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion
到0x1或0x0。用户特定设置优先于 机器设置。命令行开关优先于 注册表设置。
如果启用了延迟环境变量扩展,那么感叹号 character可用于替换环境变量的值 在执行时。
答案 6 :(得分:2)
以下批处理文件会在每个程序之后启动一系列延迟程序。
问题是传递一个带有每个程序参数的命令行。这需要围绕程序参数的引号,这些引号在进行调用时被删除。这说明了批处理文件处理中的一些技术。
查看本地子例程: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
答案 7 :(得分:2)
我知道实际上并不是作者,但是如果你需要在没有引号的情况下将一些文本发送到文件 - 下面的解决方案适合我。您不需要在echo命令中使用引号,只需用括号括起整个命令。
(
echo first very long line
echo second very long line with %lots% %of% %values%
) >"%filename%"
答案 8 :(得分:1)
使用FOR命令去除周围的引号是我发现这样做的最有效方法。在紧凑的形式(例2)中,它是一个单行。
示例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
)
示例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
我觉得有趣的是内部回声忽略了重定向字符'&lt;'和'&gt;'
如果执行ECHO asdfsd>asdfasd
,您将写出文件而不是标准输出。
希望这会有所帮助:)
修改强>
我想到了它,并意识到有一种更容易(而且不那么黑客)的方式来完成同样的事情。使用增强变量替换/扩展(请参阅HELP SET
),如下所示:
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
ECHO %STR:~1,-1%
这将打印除了第一个和最后一个字符(引号)之外的所有字符。我也建议使用SETLOCAL ENABLEDELAYEDEXPANSION
。如果您需要确定字符串中的引号位置,可以使用FINDSTR来获取字符#s。
答案 9 :(得分:1)
DanielBudzyń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
如果您尝试使用不带引号的简单回显,由于变量中的“ <”,您将得到一个错误:
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
答案 10 :(得分:1)
这对我有用:
SET "SOMETHING=Complex (String) (of stuff!)"
echo !SOMETHING! >> file.txt
答案 11 :(得分:0)
蛮力方法:
echo "foo <3 bar" | sed -e 's/\(^"\|"$\)//g'
当然,这需要找到合适的sed
的Win32版本。
答案 12 :(得分:0)
http://unxutils.sourceforge.net/是一堆GNU实用程序的本机win32端口,包括sed,gawk,grep和wget。 (很抱歉,我没有足够的代表发布此评论作为评论!)