使用管道字符进行命令输出重定向

3
我试图理解另一个命令输出重定向的工作原理。
我知道如果第二个命令是find,则可以使用它作为帮助文本来查找显式。虽然findstr的帮助文本没有提到,但是也可以与findstr一起使用。
所以问题是:
如何知道其他Windows命令行命令接受来自另一个命令的输出?
我创建了一个命令行,其中我期望输出为“18:33”,但不起作用。
C:>time /T | set /P a= && echo %a%
%a%

C:>setlocal enabledelayedexpansion
C:>time /T | set /P a= && echo !a!
!a!

为什么这个不能按预期工作?

请注意,这里的重点不是将时间读到变量中。我只是不明白管道除了使用find或findstr之外还有什么用处。

3个回答

3
几乎所有可以接受输入的命令都可以使用管道符。您示例中的“SET /P”也可以使用,但需要注意一些问题。我这里不使用延迟扩展,因为它只会增加复杂性。
time /T | ( set /P var= && set var )

这里的括号很重要,否则隐式顺序会受到影响。
( time /T | set /P var= ) && set var

但是这种方法会失败,因为管道会为两端分别创建两个新的cmd.exe实例。
在两个任务结束后,这些实例将被删除。
因此,只有在同一个(新的)实例中才能访问由管道创建的变量。

对于许多情况,管道很有用,可以自动化一些简单的问题,例如

echo Y | del *

关于管道和延迟扩展的更多信息,请访问SO:为什么在代码块内使用管道时延迟扩展失败?


1
读取文件中的命令通常但并非总是支持从处理程序 STDIN 中读取数据。管道字符 | 将应用程序 A 写入到处理程序 STDOUT 的输出重定向到应用程序 B 的处理程序 STDIN。有关详细信息,请阅读 Microsoft 文章使用命令重定向运算符和 SS64 文章重定向
哪些控制台应用程序支持从 STDIN 输入是文档问题。Windows 安装的只有少数几个控制台应用程序支持从 STDIN 输入。但是,有许多第三方控制台应用程序支持从 STDIN 输入。其中许多在文档中未明确说明可以从 STDIN 读取输入,而不仅仅是从指定为参数的输入文件中读取。但是,通过一次尝试很快就可以找出是否支持从 STDIN 输入数据。

支持STDIN的标准Windows控制台应用程序包括FINDFINDSTRMORESORT等。

大多数标准Windows控制台应用程序和cmd.exe的内部命令不处理文件内容,因此不支持STDIN。有关Windows标准命令的列表,请参见Microsoft的命令行参考。但是,有关Windows标准命令行命令的更多详细信息可在SS64.com - Windows CMD命令行的A-Z索引链接的网页上找到。

将一个应用程序的STDOUT重定向到另一个应用程序的STDIN非常常见,因为许多第三方控制台应用程序支持来自STDIN的输入。每个编译器/脚本解释器都会将消息写入STDOUT,将致命错误消息写入STDERR,许多GUI文本编辑器和IDE应用程序将这些消息重定向以捕获、过滤并将其打印到程序员的GUI窗口中。这种重定向使用与Windows命令解释器提供的重定向运算符>>>|相同的机制进行。

通常,所有支持从键盘输入的控制台应用程序也支持从输出或另一个应用程序或文件重定向的STDIN输入。但总会有例外,例如某些应用程序出于安全原因而设计为仅直接从键盘接受输入,而不是从句柄STDIN接受输入,例如不是应用程序或脚本应该确认/输入什么,而是通过键盘使用的真正人类用户。


命令SET用于为环境变量分配值,或将1个或多个环境变量的值输出到STDOUT,或计算算术表达式,或提示批处理用户从STDIN读取字符串。该命令不适用于从文件读取或写入文件。
但是,使用set /P和特殊语法,可以将应用程序的输出重定向到环境变量,如jeb在他的答案中所述。但这种方法很少使用,我认为原因是所需表达式的复杂性。
然而,演示代码是为了将当前时间分配给环境变量。通常有一个命令参数或另一个功能可以避免需要将文本重定向到命令或控制台应用程序的STDIN。获取具有当前时间值的环境变量也是如此。

有预定义的环境变量DATETIME。在命令提示符窗口中运行set /?并阅读所有输出帮助页面。在最后一页上列出了一些常用于批处理文件的特殊环境变量,包括DATETIME的说明。

尝试使用以下命令:

echo Current date is %DATE% and current time is %TIME%

请注意,%DATE%%TIME%返回的日期和时间字符串格式取决于Windows区域和语言设置(国家)的当前设置。因此,只有在批处理文件始终在已知日期/时间格式的同一台计算机上执行且不更改时,才使用%DATE%%TIME%。否则,最好使用wmic.exe OS get localdatetime。有关Windows上日期/时间用法的更多详细信息,请参见Find out if file is older than 4 hours in Batch file上的答案。
命令FOR可用于将应用程序输出的字符串分配给一个或多个环境变量。在命令提示符窗口中运行for /?以获取有关此命令的帮助。使用FOR的方法通常用于将应用程序输出或从文件中读取的文本分配给环境变量。
批处理文件示例:
@echo off
for /F %%I in ('time /T') do set "a=%%I"
echo Time is %a%

刚刚在原问题中添加了一条评论。我的观点不是将时间读入变量中,我只是不明白管道除了用于find或findstr之外还有什么用处。 - Dlanod Kcud
@Mofi 我想你只是忘记了 SET /P 命令,它可以接受用户输入和标准输入。 - jeb
@jeb 没错。我从不使用 set /P(提示方法)将来自文件或其他应用程序的字符串分配给环境变量,因为我根本不想“滥用”一个为其他目的而设计的功能,即使它是可能的。因此,我真的忘记了这种方法。我也从不使用 echo Y | del *,因为这仅适用于英语Windows,而使用 del /Q * 则独立于Windows的语言。但感谢您对我的答案进行评论并纠正其中一个重要点。 - Mofi

1
简短的答案是因为Windows出了问题。你上面的命令无法正常工作没有充分的理由,这归咎于Microsoft。他们的软件经常不仅不能正常工作,而且以完全无意义的方式工作,在没有任何错误提示的情况下浪费人们的时间。如果你想要一个通常工作并且即使出现问题也通常是因为你自己的错误而不是它的错误的好的命令提示符,请尝试Linux。
话虽如此,在Windows命令提示符下有几个可以处理标准输入的命令;其中一个就是sort命令。尝试"type text.txt | sort" 看看会发生什么。
回答你的问题“如何知道?”答案是你无法知道,因为我认为没有一个关于所有处理标准输入的命令的全面列表。然而,一般来说,如果一个命令操作一个输入文件,并且需要将输入文件名指定为参数,如果这个参数是可选的,那么可以认为如果省略了该参数,命令将处理其标准输入。
此外,如果某个命令将输入文件名作为非可选参数接受,并且您指定con作为输入文件名,则可以欺骗该命令使用标准输入。因此,例如,输入type是无效的,但是尝试输入type con并观察发生了什么。

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