【问题标题】:Windows Batch: Run command in cmd window opened by a called batch?Windows批处理:在调用批处理打开的cmd窗口中运行命令?
【发布时间】:2019-07-24 09:08:40
【问题描述】:

我想运行一个批处理文件 A,它调用/启动另一个批处理文件 B,它打开一个新的 cmd 窗口。然后我想在这个新的 cmd 窗口中运行一个用户定义的命令。该命令只有在运行文件 B 后或在这个新的 cmd 窗口中才能被识别,但命令本身的调用应该写在文件 A 中(文件 B 已设置且不能更改)。我该怎么做?

据我了解,我无法访问由另一个批处理文件打开的 cmd 窗口。我写了一个简单的测试用例来说明问题,见下文。

我已经尝试过callstart。如果我在 cmd 窗口中手动运行批处理文件 B,我可以在同一窗口中运行用户定义的命令,因为当前 cmd 窗口已“更新”并且该命令被识别。

简单的测试用例: 在此示例中,文件 A 中 call scriptB.bat 之后的所有命令都将被忽略(可能是因为这些命令在旧 cmd 窗口中运行,该旧 cmd 窗口被在 B 中打开的新 cmd 窗口“覆盖”,现在处于活动状态)。如何将命令(尤其是用户定义的命令)传递到新的 cmd 窗口?

scriptA.bat:

@echo off

echo Start script!
call scriptB.bat
%user_command%
echo End script!
pause

scriptB.bat:

@echo off

set user_command=echo USER COMMAND!
cmd

输出:

Start script!
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
*my Path*>

【问题讨论】:

  • 恐怕我帮不了你。但出于好奇:你为什么需要这个?
  • 我尝试使用 Jenkins 为软件设置构建服务器,我需要通过批处理文件运行自定义构建环境/构建命令。这个自定义构建环境会打开一个新的 cmd 窗口,我可以在其中运行自定义构建命令。
  • 首先让我们明确条款。您的示例中的任何内容都不会创建新的控制台窗口。只有没有/B 选项的start 会创建一个新窗口。 cmd 只是运行 CMD shell 的一个新实例,它将继承父级的控制台窗口(如果有)。与任何其他控制台应用程序一样,cmd.exe 不会创建或托管它使用的控制台。控制台是由 Windows 7+ 中的 conhost.exe 实例托管的共享系统资源。 cmd.exe 进程甚至不一定附加到控制台。
  • 如果 scriptB.bat 真的像那样启动一个新的 cmd.exe 实例,我认为不幸的是它写得不好。它应该只设置它当前的外壳,而不是创建外壳的新实例。这样调用者就可以运行类似start "" cmd /v:on /k "scriptB.bat & "!user_command!""
  • @eryksun 感谢您的回复和信息 :-) 我找到了一种绕过在我的真实批处理脚本中创建 shell 实例的方法。这在某种程度上“解决”了我的问题。

标签: windows batch-file cmd


【解决方案1】:

在重新阅读 Q 之后,很明显用户希望在两个脚本中都设置变量,然后以某种方式覆盖脚本 B 中设置的值,而脚本 A 中的值是事后设置的。

如果不将脚本 B 更改为使用 WMIC 从注册表中读取变量名称的信息并让脚本 A 使用 SetX,或者让脚本 A 写入文件并让脚本 B 从文件中读取,这是不可能的.

但是,这将创建一个竞态条件,因为脚本 A 可能会在脚本 B 检查之前或之后设置该值。

其他脚本 B 无论如何都无法修改,如果可以,那么可以将其设置为在脚本 A 中使用普通的 SET 命令,然后让脚本 B 使用这些变量。

【讨论】:

  • 默认情况下,子进程从父进程继承其环境。可以将自定义环境传递给CreateProcessW,它可以通过CreateEnvironmentBlock 从注册表中加载,但没有自动执行此操作的选项。如果从图形 shell (Explorer) 启动 cmd.exe,它将继承图形 shell 的环境。它似乎是从注册表中重新加载它,因为图形 shell 以及其他顶级窗口由 setx.exe 发送WM_SETTINGCHANGE“环境”消息,并作为响应重新加载其环境。
  • @eryksun 感谢您对行为的详细解释!我以前不知道内部工作原理,我怀疑 CMD 同样继承了 Windows Shell 环境,而我正在思考,但我没有意识到是什么调用对此负责。这证实了该行为将与我最初考虑后建议的那样,但对原因进行了更详细的解释。你介意我用那个信息更新这个答案吗?
  • 我不介意,但我不知道这个问题是否可以普遍解决。 OP 提供的 scriptB.bat 定义了用户命令,但随后运行了一个新的 CMD 实例,因此任何尝试运行诸如 cmd /v:on /c "scriptB.bat & "!user_command!"" 之类的命令序列的任何尝试都将被卡住,等待该 shell 实例在之前手动退出命令行的其余部分可以运行。 OP 显然找到了一种方法来避免创建新的 shell 实例,但是我看不出还有什么问题需要解决。
  • @eryksun,不,没有办法解决这个问题,对不起,我试图给出一个可能的答案,然后解释为什么我认为它不起作用,但是你对我的描述won't work 确认了那部分,只是意味着答案是它不能完成。这是我要更改的修正案,基本上说明如果不使用某些东西来传递变量并读取它们(例如文件或通过 Reg / WMIC 从注册表中查找变量),它实际上无法完成
  • @eryksun manually exited before the rest of the command line can run. @eryksun CMD /C 是这样,但CMD /K 不是这样,如果我们使用Start "" CMD /K ""ScriptB.bat" 那么Script A 将继续而不等待Script B 到结束。我根据需要将它用于并行处理,但是你会遇到一个竞争条件,试图在运行脚本 B 后读取你设置的变量,这不是 IMO 的方式,只是指出它在技术上是可行的,只要您正在通过手波传递该变量(文件/注册/等)
猜你喜欢
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多