如何将命令输出设置为批处理文件中的变量

Posted

技术标签:

【中文标题】如何将命令输出设置为批处理文件中的变量【英文标题】:How to set commands output as a variable in a batch file 【发布时间】:2022-01-11 09:49:03 【问题描述】:

是否可以将批处理文件的语句输出设置为变量,例如:

findstr testing > %VARIABLE%

echo %VARIABLE%

【问题讨论】:

Batch equivalent of Bash backticks 的可能重复项 其实原文好像是How do I get the result of a command in a variable in windows?。 Windows batch files: How to set a variable with the result of a command?的可能重复 另一个副本只是为了好玩:Windows batch assign output of a program to a variable How do I get the result of a command in a variable in windows?的可能重复 【参考方案1】:
FOR /F "tokens=* USEBACKQ" %%F IN (`command`) DO (
SET var=%%F
)
ECHO %var%

我总是使用 USEBACKQ,这样如果您有要插入的字符串或长文件名,您可以使用双引号而不会搞砸命令。

现在,如果您的输出将包含多行,您可以这样做

SETLOCAL ENABLEDELAYEDEXPANSION
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`command`) DO (
  SET var!count!=%%F
  SET /a count=!count!+1
)
ECHO %var1%
ECHO %var2%
ECHO %var3%
ENDLOCAL

【讨论】:

在Win7系统中为我工作,谢谢! (是的,这是 7 年的有用性)不要忘记在命令中将 % 扩展为 %%! 这很好用...除非输出包含感叹号 (!),因为在使用 ENABLEDELAYEDEXPANSION 时这些将被解释为控制字符 它确实工作得很好,除非你需要使用|,在这种情况下它不起作用。 @MattVukomanovic 它适用于我使用^| 代替|,如here 所述 请问是否可以捕获command 的退出代码?我确定它返回一个非零代码,但 %ERRORLEVEL% 始终包含 0,无论我在哪里尝试使用它(即使在 do 块内)。所以我猜for 构造的某些部分正在覆盖它。顺便说一句,如此基本的东西需要看起来多么疯狂的代码,这真是令人难以置信。【参考方案2】:

我在 Internet 上找到了 this thread。归结为:

@echo off 
setlocal enableextensions 
for /f "tokens=*" %%a in ( 
'VER' 
) do ( 
set myvar=%%a 
) 
echo/%%myvar%%=%myvar% 
pause 
endlocal 

您还可以将命令的输出重定向到一个临时文件,然后将该临时文件的内容放入您的变量中,如suchashereby。但它不适用于多行输入。

cmd > tmpFile 
set /p myvar= < tmpFile 
del tmpFile 

感谢 Tom's Hardware 上的线程。

【讨论】:

底部方法的唯一缺点(在所有其他方面都更可取)是它不适用于多行输出。 对于 VER,我会采取另一种方式:for /f "tokens=2 delims=[,]" %%a in ('ver') do set version %%a echo %version%跨度> 你是likesuchashereby的第二个结果-imagebin.ca/v/4NPSlQFgifce 您的第二个示例极大地帮助了我编写批处理文件来检查 chromedriver.exe 的版本与包含版本号的文本文件。我是一个老 DOS 恐龙,并且不知道设置命令的开关。其他的东西对我来说太过分了。【参考方案3】:

在一行中:

FOR /F "tokens=*" %%g IN ('*your command*') do (SET VAR=%%g)

命令输出将在 %g 中设置,然后在 VAR 中。

更多信息:https://ss64.com/nt/for_cmd.html

【讨论】:

我的批次没有以“%g”运行。它以“%%g”运行。 +Santiago Villafuerte:是的,如果您从批处理文件运行,但如果您想自己从命令行运行它(例如:在将其放入批处理文件之前对其进行测试) ) 然后你使用一个 %。 我发现 your command 有点混乱。不知道 * 是否真的有必要(否)。尽管如此非常有用的命令。【参考方案4】:

读取文件...

set /P Variable=<File.txt

写入文件

@echo %DataToWrite%>File.txt

注意; 字符前有空格会导致在变量末尾添加一个空格,也

要添加到文件中,例如记录程序, 首先创建一个文件,其中包含一个名为 e.txt 的回车键

set /P Data=<log0.log
set /P Ekey=<e.txt
@echo %Data%%Ekey%%NewData%>log0.txt

您的日志将如下所示

Entry1
Entry2 

等等

总之有一些有用的东西

【讨论】:

感谢您的回答。 BTW "set /P Variable= 你的命令 |设置 /P VAR=【参考方案5】:

这些答案都非常接近我需要的答案。这是对它们进行扩展的尝试。

在批处理文件中

如果您在 .bat 文件中运行,并且您想要一个允许您将复杂命令(如 jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json)导出到名为 AWS_ACCESS_KEY 的变量的单行代码,那么您需要这样:

FOR /F "tokens=* USEBACKQ" %%g IN (`jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json`) do (SET "AWS_ACCESS_KEY=%%g")

在命令行上

如果您在 C:\ 提示符下,您需要一行来允许您对名为 jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json 的变量运行复杂的命令到名为 AWS_ACCESS_KEY 的变量,那么您需要这样:

FOR /F "tokens=* USEBACKQ" %g IN (`jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json`) do (SET "AWS_ACCESS_KEY=%g")

说明

上面两个答案之间的唯一区别是,在命令行中,您在变量中使用了一个 %。在批处理文件中,您必须将百分比符号 (%%) 加倍。

由于命令包含冒号、引号和括号,因此您需要在选项中包含USEBACKQ 行,以便您可以使用反引号指定要运行的命令以及其中的各种有趣字符。

【讨论】:

好吧,显然有人遇到了与我在使用批处理脚本从 AWS cli 管道传输 JSON 的奇迹时所面临的完全相同的问题哈【参考方案6】:

如果您不想输出到临时文件然后读入变量,则此代码将命令结果直接存储到变量中:

FOR /F %i IN ('findstr testing') DO set VARIABLE=%i
echo %VARIABLE%

如果你想用双引号将搜索字符串括起来:

FOR /F %i IN ('findstr "testing"') DO set VARIABLE=%i

如果您想将此代码存储在批处理文件中,请添加一个额外的 % 符号:

FOR /F %%i IN ('findstr "testing"') DO set VARIABLE=%%i

一个有用的例子来计算目录中的文件数并存储在变量中: (说明管道)

FOR /F %i IN ('dir /b /a-d "%cd%" ^| find /v /c "?"') DO set /a count=%i

注意在命令括号中使用单引号而不是双引号 " 或重音 `。这是在 for 循环中替代 delimstokensusebackq 的更简洁的方法。

2021 年 8 月 27 日更新:

另一种方法是设置 errorlevel 变量,尽管许多人会在大型脚本上或刚接触已安装操作系统变体的 cmd 风格时不鼓励 setting errorlevel。

此方法适用于要存储的(返回)值为 32 位整数的情况。

例如。 计算目录中的文件数并存储在名为 errorlevel 的变量中:

(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& cmd /c exit /b %myVar%)

echo %errorlevel%
81
set /a %errorlevel%+1
82

REM Note: Win CMD arithmetic limit: 2147483647 (32-bit integers)
REM ie. an overflow would continue count at -2147483648
REM and reset again after reaching 2147483647

REM See tests below:
cmd /c exit /b 2147483647
echo %errorlevel%
2147483647

cmd /c exit /b 2147483648
echo %errorlevel%
-2147483648

cmd /c exit /b 2147483649
echo %errorlevel%
-2147483647

上面的方法可以修改为返回要在父进程中解码的编码字符串(在 32 位限制内)。

第三个插图,虽然用途有限(因为变量设置在子进程中,而不是父进程中)是:

(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& set myVar)

在这种情况下,myVar 的值设置为目录中的文件数

在 Win 10 CMD 上测试。

【讨论】:

【参考方案7】:

一些笔记和一些技巧。

将结果分配给变量的“官方”方式是使用FOR /F,尽管在其他答案中也显示了如何使用临时文件。

对于命令处理FOR 命令有两种形式,具体取决于是否使用usebackq 选项。在下面的所有示例中,都使用了整个输出而不拆分它。

FOR /f "tokens=* delims=" %%A in ('whoami') do @set "I-Am=%%A"
FOR /f "usebackq tokens=* delims=" %%A in (`whoami`) do @set "I-Am=%%A"

如果直接在控制台中使用:

FOR /f "tokens=* delims=" %A in ('whoami') do set "I-Am=%A"
FOR /f "usebackq tokens=* delims=" %A in (`whoami`) do set "I-Am=%A"

%%A 是一个仅在FOR 命令上下文中可用的临时变量,称为令牌。当您处理包含特定引号的参数时,这两种形式很有用。它对于其他语言或 WMIC 的 REPL 接口特别有用。 虽然在这两种情况下,表达式都可以放在双引号中,但仍会被处理。

这是一个python示例(可以将括号中的表达式转换为单独的行,以便于阅读):

@echo off

for /f "tokens=* delims=" %%a in (
  '"python -c ""print("""Message from python""")"""'
) do (
    echo processed message from python: "%%a"
)

要在同一 FOR 块中使用分配的变量,还要检查 DELAYED EXPANSION

还有一些技巧

为了避免为 FOR 命令编写所有参数,您可以使用 MACRO 将结果分配给变量:

@echo off

::::: ---- defining the assign macro ---- ::::::::
setlocal DisableDelayedExpansion
(set LF=^
%=EMPTY=%
)
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"

::set argv=Empty
set assign=for /L %%n in (1 1 2) do ( %\n%
   if %%n==2 (%\n%
      setlocal enableDelayedExpansion%\n%
      for /F "tokens=1,2 delims=," %%A in ("!argv!") do (%\n%
         for /f "tokens=* delims=" %%# in ('%%~A') do endlocal^&set "%%~B=%%#" %\n%
      ) %\n%
   ) %\n%
) ^& set argv=,

::::: -------- ::::::::


:::EXAMPLE
%assign% "WHOAMI /LOGONID",result
echo %result%

宏的第一个参数是命令,第二个参数是我们要使用的变量的名称,两者都用,(逗号)分隔。虽然这仅适用于直接场景。

如果我们想为控制台使用类似的宏,我们可以使用 DOSKEY

doskey assign=for /f "tokens=1,2 delims=," %a in ("$*") do @for /f "tokens=* delims=" %# in ('"%a"') do @set "%b=%#"
rem  -- example --
assign WHOAMI /LOGONID,my-id
echo %my-id%

DOSKEY 确实接受双引号作为参数的括弧,因此这对于更简单的场景也很有用。

FOR 也适用于 pipes,可用于链接命令(尽管它不太适合分配变量。

hostname |for /f "tokens=* delims=" %%# in ('more') do @(ping %%#)

也可以用宏美化:

@echo off
:: --- defining chain command macros ---
set "result-as-[arg]:=|for /f "tokens=* delims=" %%# in ('more') do @("
set "[arg]= %%#)"
:::  --------------------------  :::

::Example:
hostname %result-as-[arg]:% ping %[arg]%

对于临时文件方法的完整宏(没有doskey定义,但也很容易完成。如果你有SSD,这不会那么慢):

@echo off

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set "[[=>"#" 2>&1&set/p "&set "]]==<# & del /q # >nul 2>&1"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

chcp %[[%code-page%]]%
echo ~~%code-page%~~

whoami %[[%its-me%]]%
echo ##%its-me%##

对于 /f 与另一个宏:

::::::::::::::::::::::::::::::::::::::::::::::::::
;;set "=for /f "tokens=* delims=" %%# in ('" &::
;;set "--=') do @set ""                        &::
;;set "==%%#""                               &::
::::::::::::::::::::::::::::::::::::::::::::::::::

:: --examples

::assigning ver output to %win-ver% variable
%% ver %--%win-ver%%
echo 3: %win-ver%


::assigning hostname output to %my-host% variable
%% hostname %--%my-host%%
echo 4: %my-host%

【讨论】:

【参考方案8】:
cd %windir%\system32\inetsrv

@echo off

for /F "tokens=* USEBACKQ" %%x in (      
        `appcmd list apppool /text:name`
       ) do (
            echo|set /p=  "%%x - " /text:name & appcmd.exe list apppool "%%x" /text:processModel.identityType
       )

echo %date% & echo %time%

pause

【讨论】:

我看不出这是如何解决问题的。 appcmd 不是标准程序,我看不到您将程序输出分配给变量的位置。最后你需要更多的解释【参考方案9】:

在大多数情况下,创建一个以您的变量名命名的临时文件可能是可以接受的。 (因为您可能正在使用有意义的变量名称...)

这里,我的变量名是 SSH_PAGEANT_AUTH_SOCK

dir /w "\\.\pipe\\"|find "pageant" > %temp%\SSH_PAGEANT_AUTH_SOCK && set /P SSH_PAGEANT_AUTH_SOCK=<%temp%\SSH_PAGEANT_AUTH_SOCK

【讨论】:

以上是关于如何将命令输出设置为批处理文件中的变量的主要内容,如果未能解决你的问题,请参考以下文章

将命令的输出设置为批处理文件中的变量[重复]

批处理文件中如何将一个命令的输出赋值给一个变量

使用管道将 Windows 命令解析为批处理文件中的变量 [重复]

bat文件中批处理设置变量延迟的问题

批量设置命令的输出和错误以分隔变量

使用 Windows 批处理文件中的命令结果设置变量的值