我正在尝试创建一个运行vcvarsall.bat
batch file的简单Windows登录脚本来设置我的Visual C ++环境。 (运行Windows 7 Home Premium)。
如果在cmd.exe
的实例中运行,vcvarsall.bat
会为该cmd.exe
实例设置环境。但是,我希望在当前用户会话中设置这些环境变量。
我想要做的是将vcvarsall.bat
作为登录脚本运行。但显然单独执行此操作不会在整个Windows用户会话中保留环境变量。所以我真的想将vcvarsall.bat
作为子进程运行,当它终止时,复制子进程中与当前USER环境变量不同的任何环境变量。
有没有办法使用Windows脚本访问子进程环境?
(使用WScript.Exec()
,WScript.Run()
,WScript.CreateObject("WSHController").CreateScript().Execute()
或任何其他方法???)
答案 0 :(得分:0)
无法将子环境复制到父环境中。但是,您可以使用WshShell.Environment
对象以超出setx
命令功能的方式创建持久性环境变量。
前段时间我写了一个名为SetEnv.bat
的Batch-JScript混合脚本:
@if (@CodeSection == @Batch) @then
:: SetEnv.bat: Creation of persistent environment variables via a JScript subroutine
:: Antonio Perez Ayala
@echo off
setlocal EnableDelayedExpansion
if "%~1" neq "" if "%~1" neq "/?" goto begin
set start=
for /F "delims=:" %%a in ('findstr /N "^</*usage>" "%~F0"') do (
if not defined start (set start=%%a) else set /A lines=%%a-start-1
)
set line=0
for /F "skip=%start% tokens=1* delims=:" %%a in ('findstr /N "^" "%~F0"') do (
echo(%%b
set /A line+=1
if !line! equ %lines% goto :EOF
)
<usage>
Create persistent environment variables.
SETENV charVar=code strVar:=string ... [/T:envtype]
charVar Specifies the name of one-character environment-variable.
code Ascii (Unicode) code of the character assigned to charVar;
any code is valid, excepting zero.
strVar Specifies the name of string environment-variable.
string String of characters assigned to strVar;
if contain spaces or special characters, enclose it in quotes.
/T Specify the environment type for the variables.
envtype SYSTEM Applies to all users of the computer and is saved
between logoffs and restarts in the registry.
USER Applies to the user currently logged on to the
computer and is saved between logoffs and restarts.
VOLATILE Applies to current logon session and is not saved
between logoffs and restarts (this is the default).
PROCESS Applies to current process and might be passed to
child processes.
Examples:
[call] SetEnv BEL=7 BS=8 TAB=9 CR=13 LF=10
[call] SetEnv LastLogoff:="%date% @ %time%" /T:USER
</usage>
:begin
rem Define the variables via JScript
Cscript /nologo /E:JScript "%~F0" %*
goto :EOF
@end
// JScript section: SetEnv subprogram
// Define environment variables given in command-line arguments with this format:
// charVar=code strVar:="string" ... [/T:SYSTEM|USER|VOLATILE|PROCESS]
// Antonio Perez Ayala
// Reference: http://technet.microsoft.com/en-us/library/ee156595.aspx
var envType = WScript.Arguments.Named.Item("T");
if ( envType == undefined ) envType = "VOLATILE";
var WshShell = WScript.CreateObject("WScript.Shell"),
colEnvVars = WshShell.Environment(envType),
args = WScript.Arguments.Unnamed, name_Value, equalSignPos;
for ( var i = 0; i < args.Length; i++ ) {
name_Value = args.Item(i);
equalSignPos = name_Value.indexOf("=");
if ( name_Value.charAt(equalSignPos-1) == ":" )
colEnvVars(name_Value.slice(0,equalSignPos-1)) = name_Value.slice(equalSignPos+1);
else {
colEnvVars(name_Value.slice(0,equalSignPos)) = String.fromCharCode(parseInt(name_Value.slice(equalSignPos+1)));
}
}
这样,您只需修改vcvarsall.bat
并将set varname=value
命令替换为等效的call SetEnv varname:="value"
命令;只需注意需要在字符串变量中使用冒号相等的SetEnv语法。
编辑:作为回复评论的新方法
@if (@CodeSection == @Batch) @then
@echo off
setlocal EnableDelayedExpansion
rem Get the list of current environment variables
set "v="
for /F "delims==" %%a in ('set') do set v[%%a]=def
rem Call vcvarsall.bat to create new variables
call "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat"
rem Create a file with just the newly created variables and values
(for /F "tokens=1* delims==" %%a in ('set') do (
set "v=%%a"
if "!v:~0,2!" neq "v[" if not defined v[%%a] echo %%a=%%b
)) > vcvars.txt
rem Call JScript code to define persistent variables
Cscript /nologo /E:JScript "%~F0" < vcvars.txt
del vcvars.txt
goto :EOF
@end
var WshShell = WScript.CreateObject("WScript.Shell"),
colEnvVars = WshShell.Environment("Volatile");
while ( ! WScript.Stdin.AtEndOfStream ) {
var line = WScript.Stdin.ReadLine();
var pos = line.indexOf("=");
colEnvVars(line.slice(0,pos)) = line.slice(pos+1);
}
答案 1 :(得分:0)
以下是使用set
命令和WSH / JavaScript组合的解决方案。我们的想法是让进程vcvarsall.bat
将其环境转储到标准输出(h / t @arx here),然后将环境变量复制到&#34; volatile&#34;环境 - 即持续到用户重新启动的环境。
var shell = WScript.CreateObject("WScript.Shell")
var session_env = shell.Environment("Volatile")
// Run 'vcvarsall.bat' and then print its environment variables to standard out
// as described here: https://stackoverflow.com/a/21223991/1911388.
var vcvarsall_bat = "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat"
var script = shell.Exec("cmd /C \"" + vcvarsall_bat + "\" && set")
var stdout = script.StdOut
// Read the environment variables from the script's standard output with method
// described here: https://groups.google.com/d/msg/microsoft.public.scripting.wsh/cwg0QudGp4Y/-wunGEk6sw0J.
// For each line that is a valid environment variable assignment of value X, set
// the variable in the user environment to X if-and-only-if it isn't already set
// to X.
do
{
WScript.Sleep(10)
while (! stdout.AtEndOfStream)
{
var line = stdout.ReadLine()
var match = /^([^=]+)=(.*)$/.exec(line)
if (null != match)
{
var varname = match[1]
var varval = match[2]
var prevval = session_env(varname)
if (prevval.toLowerCase() != varval.toLowerCase())
{
session_env(varname) = varval
}
}
}
}
while (0 == script.Status && ! stdout.AtEndOfStream)
将上述内容设置为here所述的登录脚本,我可以在登录Windows时直接从任何shell或Makefile运行cl.exe
或任何我需要的VC工具。