批处理在 for /f 命令中过早关闭

7

我有一个批处理文件(在启用命令扩展的Windows XP中),其中包含以下行:

for /f %%s in ('type version.txt') do set VERSION=%%s

在某些计算机上,它可以正常工作(如这个SO问题所示),但在其他计算机上它会关闭cmd(控制台窗口会立即关闭)。
为什么?
注意:这些计算机似乎具有类似的配置:XpSP2,用户具有管理员权限,在HKEY_CURRENT_USER\Software\Microsoft\Command Processor中未定义“命令处理器”...

1
谢谢你的修改,Oli: 我本来想给那个问题打上“脚本”标签,但是 Stack Overflow 的自动补全功能把我误导了 ;) - VonC
5个回答

5

我得到了一个初步的答案:

for /f %%s in (version.txt) do ...

在每台计算机上都可以正常使用。

似乎 for /f 只能与文件名一起使用,而不能与任何 dos 命令(如 'type filename')一起使用。

然而,并非所有客户端的计算机都是这样(有些计算机上,“type filename”可以正常工作)。

如果您想获得 15 分(容易吗?),您可以回答以下问题:
为什么“for /f”有时无法与文件名以外的任何东西一起使用。为什么它只关闭 DOS 会话?


编辑:三年后(!),barlop 遇到了类似的情况,在问题 "for /f closes cmd prompt immediately?" 中详细说明了这种情况。他的结论是:

在执行 SET+ENTER 后,确实列出了 COMSPEC
因此,我打开了环境变量窗口,发现 COMSPEC 没有列在用户或系统变量下。我将其添加到了系统变量中,启动了一个命令提示符,看起来工作正常。

这个ss64 论坛上的帖子,由 Andriy M 在回答 barlop 的问题时提到,其中包含了详细信息。

在“for”循环中调用外部程序(完成“dir”或其他命令)需要设置 ComSpec 以重新加载 cmd 窗口。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\ComSpec=
%SystemRoot%\system32\cmd.exe

也许提供15分并不够好? :-) 说实话,我无法重现您提到的行为。您能否发布更多详细信息? - Tomalak
谢谢你,Tomalak,抽出时间来检查这个问题。问题是,除了已经提到的一个细节之外,我没有太多的细节:在一个客户端的PC上,在DOS会话中,我键入“for /f %s in ('type afilename.txt') do echo %s”,然后...“噼里啪啦”就没有DOS窗口了... - VonC
@VonC 为什么你接受了自己的答案,而它并没有回答问题呢? - barlop
@VonC,除非你能证明它是无法解决的,否则这将是一个好答案,那么它就不应该有一个被接受的答案。你的“答案”只是问题的阐述。如果这是一个好主意,那么系统可能会在一定时间后重复问题并将其作为答案接受。如果页面上没有答案,它应该在“无答案”列表中,以及其他数百或数千个未被回答的问题。 - barlop
@VonC 先不考虑您接受一个只是重复问题并引起非答案关注的非答案的奇怪做法。实际上,问题已经得到回答,在这里,有人提出了一个解决方案,对他有效。http://stackoverflow.com/questions/7236499/for-f-closes-cmd-prompt-immediately - barlop
显示剩余2条评论

1
关于命令扩展,有可能会使用 /E:OFF 调用 CMD.EXE 以禁用命令扩展(即使在注册表中启用)。
如果在脚本中使用命令扩展 shell 选项,强烈建议在脚本开头执行以下技巧。
-- 信息来自 http://www.ss64.com/nt/setlocal.html SETLOCAL 如果给定参数将设置 ERRORLEVEL。如果给定其中两个有效参数之一,则为零,否则为一。
您可以在批处理文件中使用此方法来确定是否可用命令扩展:
VERIFY errors 2>nul
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 echo Unable to enable extensions

这个可以运行的原因是,“VERIFY errors”会将ERRORLEVEL设置为1,如果扩展不可用(例如脚本在command.com下运行),那么SETLOCAL将无法重置ERRORLEVEL值。如果命令扩展被永久禁用,则SETLOCAL ENABLEEXTENSIONS也无法恢复它们。

感谢您提供这么详细的答案,但是我还是没有成功。那个DOS窗口仍然会自动关闭,即使ENABLEEXTENSIONS已经成功激活了... - VonC

0

是因为文件没有扩展名,所以命令提示符将其视为不存在的目录吗?


实际上,该文件存在且具有扩展名(文件名只是一个占位符名称):“for /f %s in ('type afilename.txt') do echo %s” 触发立即关闭 DOS 窗口。 - VonC

0
如果禁用命令扩展,则 for 命令的 (set) 参数必须是文件。
如果启用了命令扩展,则 for 命令的 (set) 参数可以是文件、字符串或命令。
在客户端计算机上禁用命令扩展,导致 'type filename' 设置失败。
有关启用或禁用命令扩展的信息,请键入 "cmd /?"。

他提到命令扩展被激活了(我猜是一直这样)。 - Tomalak
是的,但根据Craig的评论,我会再次检查。为了确保,Craig,您能否明确验证命令扩展是否启用的标准? - VonC
该死...我刚刚检查了注册表并重新检查了一遍,命令扩展确实已启用,并且没有其他特殊值。Windows事件没有显示任何异常情况。cmd /E:ON仍然在for /f in ('command')命令行上自动关闭...真让人沮丧 ;) - VonC
如果我没记错,CMD.EXE可能是通过/E:OFF调用的,从而禁用了命令扩展。我建议您在DOS shell中运行以下命令: VERIFY errors 2>nul SETLOCAL ENABLEEXTENSIONS IF ERRORLEVEL 1 echo 无法启用扩展 - Philibert Perusse

0

等一下...难道你在文件名周围加了撇号吗? 微软说文件名集使用双引号,而字面字符串则使用撇号。

for /F ["usebackqParsingKeywords"] {%% | %}variable in ("filenameset") do command [CommandLineOptions]

for /F ["usebackqParsingKeywords"] {%% | %}variable in ('LiteralString') do command [CommandLineOptions]

for /F ["usebackqParsingKeywords"] {%% | %}variable in (`command`) do command [CommandLineOptions]

除非你当然正在这样做。

您可以在一个立即字符串上使用 for /F 解析逻辑,方法是将 filenameset 用单引号括起来(即 'filenameset')。Filenameset 被视为文件的一行输入,然后进行解析。


谢谢Keng的建议,我明天上班会去查看。 - VonC
啊...不行:最后一个表单(command)会立即关闭DOS窗口。 - VonC

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