我正在尝试制作一个程序,选择一个文件名,然后将其传送到一个变量中。
我的尝试:
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 循环是一步解析的。您需要启用延迟扩展( ),然后使用来查看循环内设置的值。myVar
setlocal enableDelayedExpansion
echo !myVar!
还可能存在另一个问题 - FOR /F 会将值解析为空格分隔的标记,并且仅捕获第一个标记。如果您的文件名包含空格,则除非您使用 DELIMS 选项指定无分隔符,否则您将无法获得整个名称。
for /f "delims=" %%F in (....) do ....
但没有必要使用DIR /B
和。您可以简单地使用没有选项的FOR /F
vanilla循环。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 文件夹只包含一个文件,否则这两种方法似乎都不是一个好主意。
如果您需要将所有文件捕获到变量中,则需要使用伪数组。批处理没有正式的数组概念,但可以轻松模拟。如果您在网上搜索“批处理文件数组”,就可以找到大量示例