Use environment variable set by a batch script in the next batch script run

5.1k views Asked by At

Actually i want to run 2 bat scripts , first script will set a system variable set NEWPATH="E:/Some" and second script will show the path of that variable: echo %NEWPATH%. this is not working with the same server at first time , when i restart server that will show the path otherwise it'll show nothing. so can anyone help me on that?

1

There are 1 answers

2
kostix On

I don't fully grasp your problem, but here's a couple of observations.

Some theory

  • Environment vaiables set in a batch file (which is being executed by a shell process, cmd.exe)—or any other kind of process—can only be set for that very process.

    That is, each process has a special block with environment variables made available to it by the OS when that process is created.

    This also means that when the process which set an environment variable is finished, it's environment block is gone.

  • An environment variable can be inherited by a process which was started by the process which has set that environment variable.

What happens in your case

What this means is that if you run two batch scripts in a sequence, this means

  1. The first cmd.exe process is strated, the batch script it executed set an environment variable; then the process is gone, and its environment block is gone, too.

  2. Then another cmd.exe is started, it inherits the environment block of your host process (written Go), but as you can see, whatever is set by a first batch script is not available.

What you can do about it

There are two possible ways to solve the problem:

  • Make the first batch script call the second one by itself.

    In this case the second cmd.exe will inherit the environment variables set by the first script and will hence "see" them.

    Note that the Windows batch command language supports the calls command to call out to other batch scripts by their pathnames.

  • Make the first script communicate the value of that variable to your host process and then arrange in the host process for the second cmd.exe to have the indicated variable with the indicated value in its environment.

    Say, the first script could just do something like

     echo VARNAME=value
    

    to have

    VARNAME=value
    

    printed to its stdout.

    Your Go process could parse that output, tear it apart on the = character, sanitize to not affect "interesting" variables like PATH, USERPROFILE etc, and then the host process could do

    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
    

The second case can be done a bit differently: the host process can call os.Setenv("VARNAME=value") to make this variable appear in its own environment block; it then will be inherited automatically by whatever processes it starts after that.


Update to address the OP's comment

…script files will be in client side so i can't add a line echo VARNAME=value . so is there any other possible way to do this?

There's another approach which might work in your case.

The idea is that cmd.exe is just a shell: when it's started non-interactively (that's what is done by exec.Command("cmd.exe")) it reads commands from its standard input stream and executes them one by one—until the stream is closed (by the sender).

Hence you can do the following:

  1. Start cmd.exe while connecting an instance of io.Pipe to its Stdin.

  2. Open the first script yourself and shovel it at the running cmd.exe via the pipe set up on the first step.

    Don't forget to Flush() the pipe.

    You can use the io.Copy() function which sends all the data from an opened io.Reader to some io.Writer.

  3. Leave the shell instance running.

  4. When it's time, read the second script and shovel it at the same shell.

Since the shell is the same, the second script would run as if it were physically appended to the first one, and will see all the variables set by the first script.