TLDR:
set /p
命令 force CMD interpreter
是否会评估管道,即使它已转义?有可能避免这种情况吗?
考虑批处理文件中的以下行。这不是我发现的重复问题 - 如果有人问过这个问题,请指出它,我会很乐意阅读和吸收。下面代码的目的是将
Echo F | Xcopy /Y 'FilePath1' 'FilePath2'
输出到日志文件。
<nul (set /p "Lineout=Echo F ^| Xcopy /Y '%~1' '%~2'") >>%log%
我成功地按预期将字符串输出到
%log%
,但在批处理文件的控制台中,每次列出此内容时,我都会收到 Invalid Parameters
警告。我假设问题来自于 |
管道以某种方式调用 Xcopy 命令,但我不明白为什么它会这样做,即使我已经逃脱了它! (我不希望 xcopy 运行!)
Echo Echo F ^| Xcopy /Y '%~1' '%~2' >>%log%
如果我
Echo
该行具体如上所示,我在控制台上不会收到任何错误,并且我仍然得到输出,并且 xcopy 不会运行。是否只是因为管道无法逃脱,从而将 CMD
从 STDOUT 中打破并真正调用此命令?
我在一个函数中使用它,其中
args
1 和 2 是文件,但我对字符串使用单引号,因为我知道双引号会破坏 <nul set/p
文本输出方法。
是因为我在
set /p
块内执行 ()
吗?我已经在双引号内尝试过 |
、^|
和 ^^|
,但仍然收到错误,就好像 |
没有被转义一样。当我使用 2>&1
强制将 STDERR
输出到日志文件时,我什至收到错误! (因为我不在乎命令不运行,所以我愿意输出 STDERR
到日志或 nul
- 我稍后在子例程中成功运行它 - 为了清楚起见,这只是日志中的一行关于复制文件时运行的内容)
更奇怪的是 - 对于
|
和 ^|
我在日志输出中看到 ^^|
。为什么它会在 ^
中的日志中附加两 (2) set /p
?使用 ^^|
,我在日志输出中看到 ^^^^|
,但仍然收到 Invalid Parameters
错误!我需要三 (3) ^
才能正确逃脱吗?
我一定错过了一些简单的东西,或者将其归咎于管道固有的其他问题。 。 .
如果我使用管道,我是否还应该将命令的输出发送到
()
块内的 nul ,如下所示,还是会被外部重定向到 %log%
所否决?我必须假设无论我做什么,|
都不会被转义,当我执行<nul set /p
行来输出set /p
命令中的2>&1行时,STDERR
至少会是发送到日志文件或nul
,具体取决于它的解释方式。 。 .
<nul (set /p "Lineout=Echo F ^| Xcopy /Y '%~1' '%~2' >nul 2>&1") >>%log%
我想假设管道只是执行块内其右侧的命令,并且块外部的重定向正在按照人们对
()
中任何代码块的预期工作
我相信“set /p 命令是否强制 CMD 解释器评估管道,即使它已转义?是否可以避免这种情况?”的答案。是“是的,有条件。”
正如 @Mofi 的评论中提到的,
<nul (set /p "lineOut=Echo F | Xcopy /Y '%~1' '%~2'")>>%log%
的初始使用按预期工作。 。 .
我最初提出问题时没有考虑到(因为我认为这并不重要),当特定的情况下,当它作为另一个例程的另一个参数发送时,字符串
Echo F | XCopy /Y '%~1' '%~2'
是否会以相同的方式解释处理用例。
我假设这两个代码示例是等效的 - 它们不是。
REM Works as expected where '%~1' and '%~2' are file paths enclosed in a double quote line to be sent to a file.
<nul (set /p "lineOut=Echo F | Xcopy /Y '%~1' '%~2'")>>%log%
REM Does NOT work where %* contains the string listed above:
<nul (set /p "lineOut=:RoutineName %*")>>%log%
我第一次测试时认为被认为是等效的用例场景如下所示。直到进行更多测试后,我才将 %* 确定为最大的影响因素。
正如 @Mofi 在另一条评论中所述,使用
%*
会失败,因为 |
(以及其他运算符 - &<>
)将被直接解释,因为它们被从 " string "
上下文中剥离出来并且不能被解释为字符串。
REM Does NOT work - the CMD Interpreter fails to ignore the pipeline when using this approach.
Call :WriteOut "Echo F | Xcopy /Y '%~1' '%~2'" %log% "Yes"
:WriteOut [Verbiage] [Log File] [To Log?]
REM This is the line which I thought compared Apples to Apples. It does NOT!
<nul (set /p "lineOut=:WriteOut %*") >>%log%
REM This line worked fine
<nul (set /p "lineOut=%~1")
REM this line also worked fine
if not "%~3"=="" (
<nul (set /p "lineOut=%~1")>>%log%
)
我发现如果我根据需要使用另一个参数,我可以有效地将其正确输出到日志,没有错误:
REM with Parameter 4, we have success.
Call :WriteOut "Echo F | Xcopy /Y '%~1' '%~2'" %log% "Yes" "Yes"
:WriteOut [Verbiage] [Log File] [To Log?] [Lineout Contains Special Characters?]
If "%~4"=="" (
<nul (set /p "lineOut=:WriteOut %*") >>%log%
) else (
>>%log% Echo(:WriteOut %*
)
REM . . . code . . .
我也可以像过去一样这样做(没有意识到这也在我遇到问题之前解决了我的问题)
:WriteOut [Verbiage] [Log File] [To Log?] [Lineout Contains Special Characters?]
REM Break apart Args supplied, and send output safely to log file
For %%a in (%*) do (
set /a argCnt+=1
REM Assumes you have !cr! and !lf! defined appropriately previously
<nul (set /p "lineOut=:WriteOut Arg!argCnt! = %%~a!cr!!lf!")>>%log)
)
REM . . . Code . . .