Dir 通过管道传输到 Set

Dir 通过管道传输到 Set

我正在尝试制作一个程序,选择一个文件名,然后将其传送到一个变量中。

我的尝试:

Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)

使用后,它会发出

myVar:1.14.4

计划是让它进入并回显命令所以我把它做成这样

@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k

但所发生的只是

e

我做错了什么?另外,有没有办法用 FOR 来做到这一点?

答案1

我究竟做错了什么?

很简单 - 您正在尝试使用一种无​​法工作的技术;-) 由于 Windows 管道的工作方式,无法使用管道命令输出在您的父环境中设置环境变量。

您的脚本正在命令进程中运行 - 我们称之为父级。

Windows 管道启动两个子命令进程,每个进程都有自己独立的环境空间。管道左侧在第一个子进程中执行,右侧在第二个子进程中执行。管道将第一个子进程的输出作为第二个子进程的输入。成功SET /P在子进程中定义新的 myVar 变量,SET MYVAR命令显示该值。太棒了。

但随后管道结束,两个子进程都终止,其相关环境也消失。无法将 myVar 环境值从子管道进程转移回父环境。

Windows 管道设计有许多令人惊讶的副作用,让那些不完全理解该机制的人感到困惑。请参阅https://stackoverflow.com/q/8192318/1012053了解更多信息。我建议阅读问题和所有答案。

有没有办法用 FOR 来做到这一点?

是的,在环境变量中捕获命令输出的正确方法是通过 FOR,具体FOR /F如 DavidPostill 所示。尽管他的代码中有一个明确的问题、一个潜在的问题和一个低效率。

USEBACKQ处理命令的输出时无需使用。使用常规单引号'比使用反引号更简单:for /f %%F in ('yourCommand') do ...

错误在于 FOR 循环体中的使用。这将显示循环运行之前存在的echo myVar:%myVar%值,因为百分比扩展发生在解析行时,而整个 FOR 循环是一步解析的。您需要启用延迟扩展( ),然后使用来查看循环内设置的值。myVarsetlocal enableDelayedExpansionecho !myVar!

还可能存在另一个问题 - FOR /F 会将值解析为空格分隔的标记,并且仅捕获第一个标记。如果您的文件名包含空格,则除非您使用 DELIMS 选项指定无分隔符,否则您将无法获得整个名称。

for /f "delims=" %%F in (....) do .... 

但没有必要使用DIR /B和。您可以简单地使用没有选项的FOR /Fvanilla循环。FOR/F

例如,下面将简单列出所有文件:

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF

指定~nx仅使用文件名和扩展名,丢弃驱动器和文件夹路径。

通常不需要使用环境变量 - 只需%%F在循环中使用 FOR 变量即可完成工作。

但如果出于某种原因你确实需要循环之外的值,你当然可以这样做

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"

但这只会捕获迭代的最后一个文件。每次迭代都会覆盖 myVar 变量。您的原始设计将捕获列出的第一个文件(假设它可以工作)。除非您确实知道 Van1 文件夹只包含一个文件,否则这两种方法似乎都不是一个好主意。

如果您需要将所有文件捕获到变量中,则需要使用伪数组。批处理没有正式的数组概念,但可以轻松模拟。如果您在网上搜索“批处理文件数组”,就可以找到大量示例

相关内容