【问题标题】:batch - echo all variables set IN the batch file批处理 - 回显批处理文件中设置的所有变量
【发布时间】:2017-06-11 08:53:36
【问题描述】:

假设我有这个代码:

@echo off
set "var=value"
echo %var%

现在我的问题是:如何回显文件中设置的所有变量?

我知道你可以做到:

set

它会显示所有变量。它显示:

ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\foma\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
...

我希望它显示:

var=value

我知道我可以使用set var 来显示以var 开头的所有变量,但在我的情况下,我的所有变量都是从另一个批处理文件“导入”的,所以我不知道变量名称是如何开始的。 有什么想法吗?

【问题讨论】:

  • 清除所有变量的环境,然后设置您需要的变量。看到有关此技术的讨论,因为它在某些情况下有助于提高性能。
  • @Squashman 我不建议这种解决方案。它需要深入研究您将要使用的所有命令以及操作系统已配置的所有环境变量。甚至更容易遵循命名约定并决定让脚本中的变量以给定模式开头,然后使用findfindstr 查找该模式。但即使这样也存在不便,即无法检测到对现有变量的更改。也许OP可以给出更多的规范。
  • @HackR_360 你会用它做什么?只是为了撤消对环境的更改吗?您是否还需要检测对脚本执行之前存在的变量所做的更改?回答这些问题可能会导致更简单的(一个命令)解决方案。
  • @J.Baoby ,我希望我的程序: 1. 将调用的批处理文件中的所有变量回显到 .txt 文件2。允许用户修改被调用批处理文件的变量 3. 使用被调用批处理文件的所有变量创建另一个批处理文件。

标签: batch-file cmd environment-variables


【解决方案1】:
@echo off
setlocal
set>originalfile.txt
...
:: list environment changes
set|findstr /x /L /g:originalfile.txt

应该有效 - 对起始值进行快照,然后 findstr 行应该显示所做的所有更改(删除除外) - 至少在理论上,这只是一个即时建议。

【讨论】:

  • 一个很好的 bat 文件反射实现!
  • +1 - 这适用于大多数值。但如果 originalfile.txt 包含 \" 或 \\ 由于使用 g:file 时出现 FINDSTR 转义问题,它可能会失败
  • 首先将originalfile.txt中的所有\ 加倍,然后用更多代码将"替换为\",这样代码就可以(几乎)适用于所有值;不应该吗,@dbenham?也向我 +1!
  • 我收到错误消息FINDSTR: Search string too long. 但即使它有效,这不只是打印所有未更改变量吗?
  • 正确 @KlitosKyriacou,此代码需要 /V 选项和 FindStr。如果再加上你必须在几乎每一行中加倍字符的事实,那么这是一个非常错误的答案,不满足任何要求,我很惊讶它得到了任何赞成票。
【解决方案2】:

这会将原始cmd 环境(保存到文件)与当前环境进行比较。如果您需要不同的检查,您可以更改文件创建

@echo off
    setlocal enableextensions disabledelayedexpansion

    rem We need a temporary file to store the original environment
    for %%f in ("%temp%\original_%random%%random%%random%.tmp") do (

        rem Retrieve the original environment to the temporary file
        start /i /wait /min "" "%comspec%" /c">""%%~ff"" set "

        rem We need two flag variables. Prepare two names that "should" not collide
        for /f "tokens=1,2" %%d in ("_&d&%random%%random%_ _&m&%random%%random%_") do (

            rem %%d will be used to determine if we will check for variable deletion 
            rem     on the first inner pass
            rem %%e will be used for matching variables between existing/original variables
            set "%%d="

            rem Retrieve the current environment contents
            for /f "delims= eol==" %%a in ('set') do (

                rem We have not found matching variables
                set "%%e="

                rem Search a match in original set of variables 
                for /f "usebackq delims= eol==" %%o in ("%%~ff") do (

                    rem If variables match, flag it, else check for variable 
                    rem deletion is this is the first loop over the original file
                    if %%a==%%o ( set "%%e=1" ) else if not defined %%d (
                        for /f "delims==" %%V in ("%%~o") do if not defined %%V (echo(%%V=)
                    )
                )

                rem If no match found, output changed value
                if not defined %%e (echo(%%a)

            rem Now all the variable deletion has been checked.
            ) & if not defined %%d set "%%d=1"

        rem Cleanup flag variables
        ) & set "%%d=" & set "%%e="

    rem Cleanup temporary file
    ) & del "%%~ff"

删除 cmets 后,代码不像看起来那么多

@echo off
    setlocal enableextensions disabledelayedexpansion
    for %%f in ("%temp%\original_%random%%random%%random%.tmp") do (
        start /i /wait /min "" "%comspec%" /c">""%%~ff"" set "
        for /f "tokens=1,2" %%d in ("_&d&%random%%random%_ _&m&%random%%random%_") do (
            set "%%d="
            for /f "delims= eol==" %%a in ('set') do (
                set "%%e="
                for /f "usebackq delims= eol==" %%o in ("%%~ff") do (
                    if %%a==%%o ( set "%%e=1" ) else if not defined %%d (
                        for /f "delims==" %%V in ("%%~o") do if not defined %%V (echo(%%V=)
                    )
                )
                if not defined %%e (echo(%%a)
            ) & if not defined %%d set "%%d=1"
        ) & set "%%d=" & set "%%e="
    ) & del "%%~ff"

编辑只是为了完成。正如 dbenham 指出的那样,前面的代码无法处理名称或值中带有换行符的变量。这是一个可以处理这种情况的混合批处理文件(另存为 checkEnvironment.cmd 文件)。

@if (@This==@IsBatch) @then /* Batch zone ------------------------------------
@echo off
    setlocal enableextensions disabledelayedexpansion
    call :processCurrentEnvironment "%~f1"
    goto :eof

:processCurrentEnvironment 
    call "%systemroot%\system32\cscript.exe" //nologo //e:JScript "%~f0" /saved:"%~1"
    goto :eof

*/ @end
// Javascript zone -----------------------------------------------------------

var environment = WScript.CreateObject('WScript.Shell').Environment('PROCESS');
var savedFileName = WScript.Arguments.Named.Item('saved');


    if ( !savedFileName ){
        // If no saved file name present, output current environment
        for ( var e = new Enumerator(environment); !e.atEnd(); e.moveNext()){ 
            WScript.StdOut.Write( e.item() + '\0\r\n' );
        };

    } else {
        // Retrieve saved environment to compare against current one
        var savedEnvironment = retrieveSavedEnvironment( savedFileName );

        // For each element in the current environment
        for ( var e = new Enumerator(environment); !e.atEnd(); e.moveNext() ) {

            // retrieve { variable: , value: } representation of the variable 
            var buffer = splitEnvironmentVariable( e.item() );

            if ( buffer ) {
                // if the current variable does not exist in the saved version
                // or if the current value does not match the previous one
                // then dump the current variable
                if (
                    !  savedEnvironment[buffer.variable]
                    || savedEnvironment[buffer.variable].value !== buffer.value
                ) outputVariable( buffer );

                // in any case, this is a processed variable
                delete savedEnvironment[buffer.variable];
            }
        };

        // any saved variables still present are deleted variables, show them
        for (var e in savedEnvironment) outputVariable( e );
    };

// - Helper functions ----------------------------------------------------------

// Process the contents of the saved file to generate a { {variable: , value: }, ... }
// representation of the saved environment

function retrieveSavedEnvironment( savedFileName ) {
    var savedEnvironment = {};
    var buffer = readFile( savedFileName ).split('\0\r\n');
    for (var i in buffer) if ( buffer[i] = splitEnvironmentVariable(buffer[i]) ) {
        savedEnvironment[buffer[i].variable] = buffer[i];
    };
    return ( savedEnvironment );
};

// Read the contents of the saved file - FSO can not be used because we are 
// writing nulls (ascii 0x00 character) to separate variables

function readFile( savedFileName ){
    var buffer = "";
    if (
        WScript.CreateObject('Scripting.FileSystemObject').FileExists( savedFileName )
    ){
        var stream = WScript.CreateObject('ADODB.Stream');
        stream.Open();
        stream.Type = 2
        stream.Charset = 'ascii';
        stream.LoadFromFile( savedFileName );
        buffer = stream.ReadText();
        stream.Close();
    };
    return ( buffer );
};

// Convert variable=value to { variable: , value: }

function splitEnvironmentVariable( text ){
    text = (/^([\s\S][^=]*)=([\s\S]+)/).exec( text ); 
    return (
        text 
        ? { variable : text[1] , value : text[2] } 
        : text
    );
};

// Write the variable with its value or only the variable name 

function outputVariable( variable ){
    if ( typeof variable === 'object' ) {
        WScript.StdOut.WriteLine( variable.variable + '=' + variable.value );
    } else {
        WScript.StdOut.WriteLine( variable + '=' );
    };
};

放置在你的批处理文件的路径或同一个文件夹中,你可以把它当作

@echo off
    setlocal enableextensions enabledelayedexpansion

(SET LF=^
%=this line is empty=%
)

    rem Variables to delete
    set "variableToDelete=1"
    set "my!lf!var1=my!lf!data"

    set "originalEnvironment=%temp%\original_%random%%random%%random%.tmp"

    rem save environment 
    >"%originalEnvironment%" call checkEnvironment.cmd

    rem Create new variable2
    set "thisIsNew=value"
    set "anotherOne=1"

    rem Create another problematic variable
    set "my!lf!var2=my!lf!data"

    rem Delete variables
    set "variableToDelete="
    set "my!lf!var1="

    rem Dump environment changes
    call checkEnvironment.cmd "%originalEnvironment%"

    rem Remove temporary file
    del /q "%originalEnvironment%"

以退出为

W:\>testEnv.cmd
anotherOne=1
my
var2=my
data
thisIsNew=value
my
var1=
variableToDelete=
W:\>

【讨论】:

  • 非常好。为我工作。当然,如果变量值(或名称!)包含换行符,这将失败,但我认为没有任何批处理解决方案可以处理这个问题。我相信 OP 想要探究最近的批处理文件做了哪些更改,而不是自命令会话开始以来进行了哪些更改。但您承认可以根据需要更改文件创建。
  • @dbenham,我看不到如何处理纯批处理中的新行。以防万一有人觉得它有用,我提供了一个混合版本来处理它。
【解决方案3】:

无论如何最简单的方法:

@echo off
setlocal enabledelayedexpansion
set "oldfile=oldfile.txt"
set "newfile=newfile.txt"
del %oldfile% >nul 2>nul
del %newfile% >nul 2>nul
for /f %%a in ('set') do echo %%a>>%oldfile%
::---------------------set-vars-here---------------------
set "testone=testonestring"
set "testtow=12324"
::-------------------------------------------------------
for /f %%a in ('set') do echo %%a>>%newfile%
for /f %%a in (%newfile%) do (
find "%%a" %oldfile% >nul 2>nul
if !errorlevel! NEQ 0 (
set "string=%%a"
echo !string!
)
)
del %oldfile% >nul 2>nul
del %newfile% >nul 2>nul
pause

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    相关资源
    最近更新 更多