我有一个调用工具的批处理文件。现在我在批处理文件的 for 循环中遇到了一个问题。但是尽管我对批处理脚本进行了所有研究,我仍然无法弄清楚表达式想要表达什么。经过几天的挖掘,我转向这个论坛寻求帮助。for 循环如下:
for /f "tokens=1-3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( @echo Debug Output: %%g set JAVAVER=%%g )
我知道这是一个 for 循环,试图设置 JAVA 版本并运行不同的文件,但问题是它没有执行预期的任务,因此我需要进一步了解下面一行的评估内容:
('java -version 2^>^&1 ^| findstr /i "version"')
更让我困惑的是,如果我单独运行以下命令,它会给出如下所示的输出,其中没有任何“版本”文本。但是,如果我与上述命令一起运行,则会给出当前 Java 版本的输出。
代码:
for /f "tokens=3" %%g in ('java -version 2^>^&1') do ( @echo Debug Output: %%g set JAVAVER=%%g )
输出:
Debug Output: "1.8.0_231"
Debug Output: Runtime
Debug Output: 64-Bit
回复Doug Deden的示例:
当我执行以下操作时,它确实显示 echo 命令输出。
for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
@echo Debug Output: %%g
set JAVAVER=%%g
@echo %JAVAVER%
)
但是,当我通过删除来执行上述操作时2^>^&1
,它不会考虑回显命令。
我的困惑是,当我把这2^>^&1
部分代码放进代码中时,标准错误被重定向到标准输出,但如果我完全删除它会发生什么?它会重定向到其他输出吗?为什么它会停止回显命令?
答案1
这一行包含了很多功能。简单的英语总结如下:
- 询问 Java 当前版本。这将提供多条信息。
- 在 Java 的输出中找到包含“version”的行。
- 找到该行上的第三个组件。
- 将其作为输出回显,并将 JAVAVER 环境变量设置为该值。
让我们把它分解一下。
for /f "tokens=1-3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( @echo Debug Output: %%g set JAVAVER=%%g )
我将从最里面的部分开始:'java -version 2^>^&1 ^| findstr /i "version"'
批处理文件告诉 Windows 运行此程序,然后批处理文件将对结果执行一些操作。
插入符号 ( ^
) 用于告诉批处理文件按字面意思处理以下字符。否则,批处理文件将尝试解释它们并将它们视为批处理文件本身的指令或修饰符。相反,我们希望批处理文件只是“按原样”传递它们。因此,批处理文件告诉 Windows 运行此命令:
'java -version 2>&1 | findstr /i "version"'
java
- 运行java.exe
,无论它在路径中的何处找到-version
- 告诉java.exe
打印版本信息并退出2>&1
- 将任何错误重定向到与标准输出相同的位置(Rob van der Woude 有一个很棒的关于重定向的页面)——你需要这个,因为 Java 将其版本信息发送到标准错误流,而不是标准输出流——参见StackOverflow 上的此问答——这使得它将版本信息发送到标准输出流,因此最终可以被findstr
|
- 将目前的结果发送到下一个程序--findstr
findstr
- 在输入中搜索字符串,这是java -version 2>&1
命令的输出/i
- 告诉findstr
进行不区分大小写的搜索"version"
- 告诉findstr
搜索什么文本
典型的输出java -version
将会像这样:
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
然后经过传递之后findstr
,只剩下包含“version”的行:
java version "1.8.0_92"
接下来,让我们看一下这个for /f
部分。for /f … in …
将查看“in”后面的命令的结果并对其进行处理。您的第一个和第三个示例的部分值不同tokens=…
,因此在复制和粘贴过程中可能丢失了某些内容。无论如何,部分tokens=…
会告诉for /f
命令要关注正在处理的行中的哪些部分(又称标记)。默认情况下,空格或制表符表示新标记。因此,参数tokens=3
会告诉for /f
查看行的第三部分,即"1.8.0_92"
。%%g
选项告诉for /f
将其找到的内容存储在变量中%g
。(需要额外的%
原因是您是从批处理文件运行此文件。如果您直接在命令提示符下运行它,则只需要一个%
。)
到目前为止,如果您使用tokens=3
,您将已"1.8.0_92"
存储在%g
变量中。(如果您改用tokens=1-3
,您将拥有"java"
in %g
、version
in%h
和"1.8.0_92"
in %i
。该for /f
命令开始将标记推入变量中,从您指定的变量开始,并按字母表递增。)
然后,该行的部分会告诉您要针对命令出现的do
每件事执行什么命令。在本例中,它执行两件事:for /f
@echo Debug Output: %%g
- 将“调试输出:”打印到标准输出,后面跟着变量的值%g
,也就是我们之前看到的"1.8.0_92"
。set JAVAVER=%%g
- 将环境变量的值设置JAVAVER
为%g
变量中的任何内容。
(Rob van der Woude 也有一个很棒的页面解释for/f 命令。
findstr
当您在某个实验中取出该部分并使用时tokens=3
,您会看到输出,表明该for /f
命令抓取了 Java 版本信息每一行上的第三个标记,这里以粗体突出显示:
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
并且该实验还会将 JAVAVER 环境变量设置为每个字符串,因此最终会得到最后一个字符串-- 64-bit
。