9

我想知道是否可以从批处理文件中的管道读取。如果我写:

echo Test

我明白了,不足为奇,Test. 那很好。但是如果我想管道输出,并从另一个命令中读取它呢?

echo Test | echo ???

如何通过管道获得与以前相同的结果?谢谢!

编辑:我真正追求的是这个。

我有一个文件列表,我需要用我在一个名为filter.txt. 所以我必须使用findstr /g:filter.txt.

但是我需要对匹配的列表文件做一些事情,因为findstr每个文件都返回一行,所以我必须逐行读取匹配项。

我就是这样做的:

dir /b | findstr /g:filter.txt | for /F "delims=" %a in ('more') do del "%a"

解决方案:

看起来我想做的不是从管道中读取,而只是读取批处理文件中另一个命令的输出。

要进行单行读取,您可以使用以下命令:

echo Test | ( set /p line= & call echo %%line%%)

或者您可以使用它,它也适用于多行输入:

echo Test | for /F "delims=" %a in ('more') do @echo %a

(这种使用更多的技巧在某些情况下可能很有用)。但在我的特殊情况下,解决方案是这样的:

for /F "delims=" %a in ('echo Test') do @echo %a

谢谢大家!

4

4 回答 4

8

基于这个答案https://stackoverflow.com/a/6980605/1630171看起来回答我的问题的方法是这样的:

echo Test | for /F "delims=" %a in ('more') do @echo %a

这有点奇怪,但它有效:)

对我来说没有本地解决方案只是看起来有点奇怪......但这正是我想要的!

于 2012-11-13T22:59:47.653 回答
7

要读取单行,您也可以使用set /p,但这仅适用于一行。

echo test | ( set /p line= & call echo %%line%%)

问题就在这里,管道为每一侧创建了两个新的 cmd.exe 上下文。
它们与父 cmd.exe 在同一窗口中运行,它们不能更改父 cmd 的任何变量,因为它们是唯一的子项。

这就是为什么这个失败的原因

echo test | set /p line=
echo %line%

line将被设置,但当管道结束时它将被销毁。

于 2012-11-13T23:21:03.110 回答
7

对不起,我认为这里有一个混乱......

你说你想从管道中读取。管道用于将一个命令的输出重定向到另一个命令的输入;第二个命令称为filter。例如,在

dir /b | findstr /g:filter.txt

dirfindstr命令之间有一个管道。管道总是在两个进程之间建立。无法读取从dir命令流向findstr命令的数据(这是此处存在的唯一管道)。但是,您可以从命令的输出中读取findstr

如果我们插入一个额外的过滤器,行为是相同的。例如,在

dir /b | findstr /g:filter.txt | more

有两个管道,但无法从其中任何一个中读取。但是,您可以从最后一个命令的输出中读取(more在本例中)。读取一个命令的输出的本机批处理解决方案是什么?它是 FOR /F 命令。例如,获取echo命令输出的本机方式:

echo Test | for /F "delims=" %a in ('more') do @echo %a

是:

for /F "delims=" %a in ('echo Test') do @echo %a

请注意,在第一个示例中,%a 参数不是从存在于echofor命令之间的管道中获取信息,而是从命令的输出中获取信息more

同理,实现这个任务的自然方法:

dir /b | findstr /g:filter.txt | for /F "delims=" %a in ('more') do del "%a"

是这样的:

for /F "delims=" %a in ('dir /b ^| findstr /g:filter.txt') do del "%a"

处理命令的多行输出findstr

第二种方法不仅比前者更快,而且更清晰,因为包含一个more实际上什么都不做的命令可能会导致不希望的误解或错误。

安东尼奥

于 2012-11-15T04:50:39.933 回答
-1

基于我在其他地方看到的另一个答案,只要它是数字的,就可以非常简单地捕获命令的输出并将其存储在没有中间文件的变量中。

子进程,如管道内的那些不能共享它们的环境变量,但可以返回一个由 %errorlevel% 获取的值。%errorlevel% 虽然不是环境变量,但每次调用时都会由 shell 计算。也不能正常设置,必须使用子进程设置。例子:

@echo off
echo %errorlevel%
cmd /c exit 56
echo %errorlevel%

回报:

0
56

有趣的是,您还可以这样做:

@echo off
echo %errorlevel%
cmd /c exit 56 & echo hi
echo %errorlevel%

回报:

0
hi
56

我相信这是因为它echo hi是由另一个子进程依次运行的,它不会在打印之前等待退出语句完成。这可能会因竞争条件而改变,但如果打印的文本更长,我不确定作为打印“hi”的父进程的子进程(运行退出)是否会等待它的子进程退出(或任何随后的孩子)在它完成退出命令之前。我尝试使用运行时间较长的命令(如 Tree)对此进行测试,但我得到一个查询返回的 0 到 %errorlevel%,这可能是由于 Tree 通过返回 0 影响结果,可能在exit 56.

无论如何,回到最有用的东西:

@echo off
echo %errorlevel%
echo 456 | ( set /p line= & call exit %%line%% )
echo %errorlevel%
pause

回报:

0
456

在这里,echo 打印的 456 被后续查询捕获并返回给 %errorlevel%。您可以通过这种方式捕获任何命令的输出,尽管它仅限于一个数值。这仍然非常有用,但不幸的是不允许您存储文本输出,我也想不出一种方法让它适用于多行输出。(未探索)

我认为理论上你可以链接任意数量的命令,并且应该能够用来&&强制它们运行的​​顺序。我不知道如何或是否可以使用它来捕获多行输入或允许返回文本,但应该通过提供向下共享其环境并可能返回值的嵌套子进程在管道内提供一些额外的摆动空间。(再次未经测试,也许尝试多个退出语句或其他东西,如果我以后学到任何东西,我会尝试在这里发布)

于 2017-03-16T14:54:46.777 回答