如何将重定向符号(<和>)传递给Windows批处理文件函数?

8
假设这是一个批处理文件。
call :SomeFunction "a string with an > arrow"

goto:eof

:SomeFunction
  echo %~1
goto:eof

这将会输出:

call :SomeFunction "a string with an > arrow"
echo a string with an  1>arrow
goto:eof
goto:eof

并且将创建一个名为arrow的文件,其中包含a string with an。请注意1>

在这种情况下,我该如何防止命令处理程序解释>作为重定向符号呢?(提示:我已经尝试过^>,但不是这个方法。)

编辑:其他运算符(|&)也受到影响。


以下是一些批处理文件中重定向的好例子。http://www.robvanderwoude.com/redirection.php - Knuckle-Dragger
3个回答

6
你可以使用FOR /F命令来代替原本的方法来实现这个目标:
echo %~1

请使用以下内容:
FOR /F "delims=" %%i IN ("%~1") DO echo %%i

编辑:请注意,现在当您传递一个用双引号分隔的参数时,需要处理奇怪的转义行为。例如,"a^2"将被转义为"a^^2",无论您尝试使用"a^^2"还是"a\^2"。根据您自己的评论,您可以使用临时变量进行转义(然后删除双引号)。

set TEMP=%TEMP:>=^>%

如果您不想关心转义,您也可以尝试以下方法:

set "tmp="many \ ^ > ' characters and quotes""

注意双引号来包含set参数以及字符串中的许多特殊字符。在这种情况下,tmp环境变量将字面上是:"many \ ^ > ' characters and quotes",您可以简单地使用它:

FOR /F "delims=" %%1 IN (%tmp%) DO echo %%1

请使用%1替代"%~1"。现在让我们来看一个更复杂的情况。如果您需要在字符串中使用双引号",那么有些字符将不会被转义(例如&|)。您可以简单地删除引号:

set "tmp=many \ ^ > ' | & characters and quotes"

使用:

FOR /F "delims=" %%1 IN ("%tmp%") DO echo %%1

或者

FOR /F "delims== tokens=2" %%1 IN ('set tmp') DO echo %%1

不要忘记,如果您指定usebackq选项,可以使用反引号来分隔FOR字符串。您可以使用临时文件或更好的PowerShell脚本...

1
@Tomalak 是的,调用函数时转义参数很糟糕(所以你可能需要使用(%1)而不是("%~1")),但是某些字符仍然需要转义。据我所知,除非使用临时文件,否则没有真正的“原始”方式可以传递未经转义的参数。 - Adriano Repetti
1
@Tomalak 我同意。它已经被扩展了很久,没有任何连贯性和很多漏洞和暗角(兼容性?)。这就是为什么我喜欢PS! - Adriano Repetti
我想我可以使用%1,将其分配给TEMP变量,用^>替换>set TEMP=%TEMP:>=^>%),如果有引号,则删除括号内的引号(%TEMP:~1,-1%),然后echo %TEMP%。这个...呃...方法是可行的,但它会让我失去理智。 - Tomalak
1
@Tomalak 不仅如此,如果您使用 set "tmp="many \ ^ > ' characters and quotes""(请注意开始和结束的双引号以及 value 的内部引号),则可以跳过转义并保留 FOR - Adriano Repetti
1
如果可以的话,我会再次为你的编辑点赞。非常有启发性! - Tomalak
显示剩余4条评论

1

就像foxidrive所提到的,CALL将会修改插入符号,因此不可能通过CALL建立一种可靠的方式来传递参数的值。
但是你可以使用参数的引用来代替。

@echo off
set "var=a string with a caret^ and an > arrow"

call :SomeFunc var
exit /b

:SomeFunc
setlocal EnableDelayedExpansion
set "param1=!%1!"
echo !param1!
exit /b

我在这里使用延迟扩展,因为这是以安全的方式处理任何变量内容的最佳方法。

1

Call^ 执行了一些奇怪的操作,但这个代码可以正常工作。

@echo off
set "var=a string with an ^> arrow"
call :SomeFunction 
pause
goto:eof

:SomeFunction
  echo %var%
goto:eof

抱歉,但那不是解决方案。我想继续使用函数参数(而不是全局变量)。 - Tomalak
+1 这不是最好的解决方案,但它展示了如何以一般方式解决问题。 - jeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接