如何将 Windows CMD 管道 ( | ) 功能与 CALL :Label 命令选项一起使用?
当我想将管道(|) 功能与Windows 的CMD shell 的CALL :Label 选项一起使用时,我遇到了一个令人沮丧的问题。我有一个非常小的示例(如下):call-test.cmd 和示例输出。
问题的核心是将 CMD 脚本的输出通过管道传输到另一个程序,例如 tee 实用程序或 find 命令。例如:
@call :Label-02 param | tee call-test.log
它将在标签 Label-02 处启动当前命令文件,并将输出通过管道传输到 tee。不幸的是,在带有“call :label”选项的行上使用管道字符(|)会产生错误:
Invalid attempt to call batch label outside of batch script.
而“call example.cmd | tee example.log”则工作得很好。
其他 IO 重定向> 工作正常。这只是使用“call :label pipeline(|)”失败的一种情况。对我来说,它看起来就像一个 Windows 错误。
有人有解决方法和/或知道解释吗?
谢谢, 将
调用测试输出
<前><代码>c:\>呼叫测试 [开始] 标签 03::p1 在批处理脚本之外调用批处理标签的尝试无效。 在批处理脚本之外调用批处理标签的尝试无效。 [完毕] 按任意键继续。 。 。调用测试
<前><代码>@echo 关闭 @rem call-test.cmd @雷姆_________________________________________________ @rem Test:.cmd 文件的标签调用选项。 @雷姆 @echo ^ [开始] @call:Label-03 p1 @call :Label-02 第二个 |寻找 ” ” @call :Label-02 第二个 | tee 呼叫测试.log @goto 完成 @雷姆_________________________________________________ :标签-01 @echo ^ 标签 01::%1 @goto 退出 @雷姆_________________________________________________ :标签-02 @echo ^ 标签 02::%1 @goto 退出 @雷姆_________________________________________________ :标签-03 @echo ^ 标签 03::%1 @goto 退出 @雷姆_________________________________________________ :完毕 @echo ^ [完成] @暂停 @雷姆_________________________________________________ :出口 @退出/b
I have a frustrating problem when I want to use the pipe(|) feature with the Window's CMD shell's CALL :Label option. I have a very small example (below): call-test.cmd and sample output.
The nub of the issue was/is to pipe the output of a CMD script to another program, for example the tee utility, or find command. For example:
@call :Label-02 param | tee call-test.log
Which would start the current command file at the label Label-02 and pipe the output to tee. Unfortunately using the pipe character(|) on the line with "call :label" option gives an error:
Invalid attempt to call batch label outside of batch script.
Whereas, "call example.cmd | tee example.log", works just fine.
The other IO redirection > works OK. It is just the one case when "call :label pipe(|)" is used that fails. To me it just looks like a windows bug.
Does anyone have a workaround and/or know of an explanation?
Thanks,
Will
call-test output
c:\> call-test [start] label 03 :: p1 Invalid attempt to call batch label outside of batch script. Invalid attempt to call batch label outside of batch script. [done] Press any key to continue . . .
call-test
@echo off @rem call-test.cmd @rem _________________________________________________ @rem Test :label call option for .cmd files. @rem @echo ^ [start] @call :Label-03 p1 @call :Label-02 second | find " " @call :Label-02 second | tee call-test.log @goto Done @rem _________________________________________________ :Label-01 @echo ^ label 01 :: %1 @goto Exit @rem _________________________________________________ :Label-02 @echo ^ label 02 :: %1 @goto Exit @rem _________________________________________________ :Label-03 @echo ^ label 03 :: %1 @goto Exit @rem _________________________________________________ :Done @echo ^ [done] @pause @rem _________________________________________________ :Exit @exit /b
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
原因是,管道在 cmd 上下文中启动两侧(两者在一个 cmd 框中并行运行),并且每一侧都被解释为真正的命令行参数,并且在 cmd 行上不允许使用标签。
但是,如果重新启动批处理,您可以调用您的函数。
编辑:完整示例
The cause is, that a pipe starts both sides in a cmd context (both run parallel in one cmd-box), and each side is interpreted as a real command line argument, and on the cmd line labels aren't allowed.
But you can call your function, if you restart your batch.
EDIT: The complete sample
明显的解决方法是将调用的输出重定向到临时文件,将其用作 find/tee 的输入,然后删除文件:
The obvious workaround is to redirect output of call to temporary file, use it as an input for find/tee, then delete file:
我意识到这来得有点晚,但可能对其他人有帮助。这不完全是一个黑客,更多的是一个解决方法。或者如果你必须的话,相当“不错的黑客”。
我正在使用以下解决方案来解决类似的问题:
它的好处是我可以将“标题”复制粘贴到我需要运行它的任何批处理脚本中。我没有费心使其递归安全因为我不需要它,所以请确保在放入之前测试该场景。
显然,我对这些 debug* 调用有包装函数,这样我就不会在每次调用时携带日志文件。另外,在我的调试日志调用中,我还测试了调试标志,因此包装器本身有更多的逻辑,这主要取决于所使用的脚本。
I realize this comes a bit late, but might be helpful for others. this isn't quite a hack, more a workaround. Or pretty "nice hack" if you must.
I'm using the following solution to a similar problem:
The nice thing about it is that I can copy-paste the "header" into any batch script I need to run it in. I didn't bother to make it recursive-safe as I didn't needed it, so make sure you test that scenario before putting it in.
Obviously, I have wrapper functions on these debug* calls, so that I don't carry around the log file with each call. Also, in my debug log calls, I also test for the debug flag, so the wrapper itself has some more logic to it, which mainly depends on the script used in.
这是 jebs 答案的更简洁版本。
它使用相同的 goto 技术,但不是在重新输入时传递唯一的“START”参数,而是使用 子字符串提取 并且仅当它是标签时才调用 goto。这简化了调用,但是您不能将子字符串提取与 %1 变量或空/不存在的变量一起使用,因此它必须使用始终包含值的临时变量。无论如何,它都需要临时变量来记住标签,因为
SHIFT /1
将删除第一个 :LABEL 参数,但它只需要使用 SHIFT 一次,并且在调用站点不需要额外的参数。[更新:必须执行
shift /1
以避免在脚本使用%0时更改它]因此以下脚本显示了如何使用传递给原始文件的参数脚本,以及重新输入处理标签:
将输出:
echo (bar)
行被管道剥离以 findstr问题的解决方案:
此脚本:
将 echo:
和
call-test.log
具有正确的内容:This is a more succinct version of jebs answer.
It uses the same goto technique, but instead of passing a unique "START" parameter when re-entering, it tests if the first character of the first parameter is ":" using a substring extraction and only calls goto if it's a label. This simplifies the call, however you can't use substring extraction with %1 variables or empty/non-existent variables so it has to use a temporary variable that always contains a value. It needs the temp var anyway to remember the label as
SHIFT /1
will remove the first :LABEL parameter, but it only has to use SHIFT once, and doesn't require an extra parameter at the call site.[update: must do
shift /1
to avoid changing %0 in case it's used by the script]So the following script shows how you can use the parameters passed to the original script, as well as re-entering to process labels:
will output:
the
echo (bar)
line being stripped by the pipe to findstrsolution to the question:
This script:
will echo:
And
call-test.log
has the correct content:我认为你可以使用“|”那么管道将被视为普通字符。
I think you can use "|" then pipe is treated as just regular character.
将
^
放在管道命令前面......例如@call :Label-02 秒 ^|找到“”
put the
^
in front of the pipe command....e.g.@call :Label-02 second ^| find " "