【问题标题】:Use environment variable set by a batch script in the next batch script run在下一个批处理脚本运行中使用批处理脚本设置的环境变量
【发布时间】:2016-12-30 06:34:02
【问题描述】:

实际上我想运行 2 个 bat 脚本,第一个脚本将设置一个系统变量 set NEWPATH="E:/Some",第二个脚本将显示该变量的路径:echo %NEWPATH%。这在第一次不适用于同一台服务器,当我重新启动服务器时将显示路径,否则它不会显示任何内容。那么有人可以帮我吗?

【问题讨论】:

  • 查看setx command 以在用户或系统上下文中永久设置环境变量(这是第三种可能的方式,@kostix)...
  • 是的,它将永久更新,但在重新启动服务器之前无法使用。 @as
  • @aschipfl,谢谢!我不知道这个命令。问题是我不知道用更新的环境块替换当前进程的环境块的任何简单解决方案。好吧,除了直接调用 Win32 API。另一个明显的问题是,在按顺序执行的两个进程之间传递单个键+值组合这种方式是一个严重的过度工程IMO:
  • @aschipfl 因为在 Windows 上,用户和系统环境块存储在注册表中,所以 OP 的服务器可以直接使用 HKCU 中的专用注册表项来实现此目的。我认为这仍然是一个过度工程,但至少规模较小:-)
  • @shagul,顺便问一下,您已经在第一个批处理脚本中使用setx 命令吗? (这可以解释“当我重新启动服务器时,它将显示路径,否则它什么都不会显示”对我来说是一段话——我最初无法理解)。

标签: batch-file go environment-variables windows-scripting


【解决方案1】:

我没有完全理解你的问题,但这里有一些观察。

一些理论

  • 在批处理文件(由 shell 进程 cmd.exe 执行)或任何其他类型的进程中设置的环境变量只能为那个进程设置。 p>

    也就是说,每个进程都有一个特殊的块,其中包含在创建该进程时由操作系统提供给它的环境变量。

    这也意味着当设置环境变量的进程结束时,它的环境块就消失了。

  • 一个环境变量可以被一个由设置了该环境变量的进程所启动的进程继承。

你的情况会发生什么

这意味着如果你按顺序运行两个批处理脚本,这意味着

  1. 第一个cmd.exe进程被分层,它执行的批处理脚本 设置环境变量;那么进程就消失了,它的环境块也消失了。

  2. 然后启动另一个cmd.exe,它继承了你的宿主进程的环境块(写成Go),但是你可以看到,第一个批处理脚本设置的任何东西都不可用。

你能做些什么

有两种可能的方法来解决这个问题:

  • 让第一个批处理脚本自己调用第二个。

    在这种情况下,第二个cmd.exe 将继承环境变量 由第一个脚本设置,因此将“看到”它们。

    请注意,Windows 批处理命令语言支持 calls 命令通过路径名调用其他批处理脚本。

  • 让第一个脚本将该变量的值传达给您的主机进程,然后在主机进程中安排第二个cmd.exe 在其环境中使用具有指示值的指示变量。

    说,第一个脚本可以做类似的事情

     echo VARNAME=value
    

    拥有

    VARNAME=value
    

    打印到其标准输出。

    您的 Go 进程可以解析该输出,并在 = 上将其拆开 字符,清理以不影响像PATH这样的“有趣”变量, USERPROFILE等,然后宿主进程就可以了

    env := os.Environ()
    env = env.append("VARNAME=value") // real value here
    ...
    cmd := exec.Command(`cmd.exe`, `/c`, secondScriptFilePath)
    cmd.Env = env
    ...
    cmd.Run() // or whatever
    

第二种情况可以做的有点不同:宿主进程 可以调用os.Setenv("VARNAME=value") 使这个变量出现在它的 自己的环境块;然后它将被之后启动的任何进程自动继承。


更新以解决 OP 的评论

…脚本文件将在客户端,所以我不能添加一行 echo VARNAME=value 。 那么还有其他可能的方法吗?

还有另一种方法可能适用于您的情况。

这个想法是 cmd.exe 只是一个外壳:当它以非交互方式启动时(这就是 exec.Command("cmd.exe") 所做的) 它从其标准输入流中读取命令并一个一个地执行它们——直到流被关闭(由发送者)。

因此您可以执行以下操作:

  1. 启动cmd.exe,同时将io.Pipe 的实例连接到它的Stdin

  2. 自己打开第一个脚本并通过第一步设置的管道将其铲到正在运行的cmd.exe

    别忘了Flush()管道。

    您可以使用io.Copy() 函数将所有数据从打开的io.Reader 发送到某个io.Writer

  3. 让 shell 实例继续运行。

  4. 时间到了,阅读第二个脚本并将其铲到同一个外壳上。

因为 shell 是相同的,所以第二个脚本运行起来就像是物理附加到第一个脚本一样,并且会看到第一个脚本设置的所有变量。

【讨论】:

  • 非常感谢您的帮助,但脚本文件将在客户端,所以我无法添加一行 [echo VARNAME=value] 。所以还有其他可能的方法吗?
  • @shagul,应该是的——请参阅我的答案的更新。
猜你喜欢
  • 1970-01-01
  • 2012-03-19
  • 2023-03-21
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 2013-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多