是否可以在批处理文件中逐行读取管道?

时间:2012-11-13 22:37:49

标签: batch-file cmd

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

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"

SOLUTION:

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

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

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

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

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

(使用 more 的这个技巧在某些情况下可能会有用)。但在我的特殊情况下,解决方案就是:

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

感谢大家!

4 个答案:

答案 0 :(得分:7)

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

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

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

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

答案 1 :(得分:7)

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

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

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

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

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

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

答案 2 :(得分: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命令可能会导致意外的误解或错误。

安东尼奥

答案 3 :(得分:-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依次由另一个子进程运行,在打印之前不会等待exit语句完成。这可能会因竞争条件而改变,但是如果打印的文本较长,我不确定子进程(正在运行的出口)是否是打印的父进程' hi'在完成退出命令之前,它将等待它的孩子退出(或任何后续的孩子)。我尝试使用像Tree这样运行时间更长的命令对此进行测试,但是我得到了一个由%errorlevel%查询返回的零,这可能是由于Tree通过返回0来影响结果,可能是在exit 56之后。 / p>

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

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

返回:

0
456

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

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