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

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

findstr testing > %VARIABLE%


echo %VARIABLE%
717184 次浏览

我在互联网上找到了这个线程。归结起来就是:

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

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

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

这要归功于汤姆硬件的帖子。

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

读取文件…

set /P Variable=<File.txt

写文件

@echo %DataToWrite%>File.txt

请注意;在<>字符之前有空格也会导致在变量的末尾添加一个空格

要添加到文件中,就像记录器程序一样, 首先创建一个文件,文件中只有一个enter键,名为e.txt

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

你的日志是这样的

Entry1
Entry2

等等

总之,有一些有用的东西

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

在一行中:

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

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

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

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

在批处理文件中

如果你在.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:\提示符下,你想要一行允许你对名为AWS_ACCESS_KEY的变量运行复杂的命令,比如jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json,那么你想要这样:

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

解释

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

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

如果你不想输出到一个临时文件,然后读入一个变量,这段代码将命令的结果直接存储到一个变量:

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
一个计算目录中文件数量的有用示例&存储在变量中: (说明管道)< / p >
FOR /F %i IN ('dir /b /a-d "%cd%" ^| find /v /c "?"') DO set /a count=%i

注意使用单引号而不是双引号"或者命令括号中的“严肃重音”。这是for循环中delimstokensusebackq的更干净的替代方法。

更新27/8/2021:

另一种方法是设置errorlevel变量,尽管许多人不鼓励在大型脚本上使用设置返回码,或者在安装的操作系统变体的cmd版本中使用设置返回码

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

< p >。 要计算目录中的文件数量&存储在名为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的值被设置为目录中的文件数量

在win10 CMD上测试。

一些笔记和一些技巧。

将结果分配给变量的“正式”方式是使用< >强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命令上下文中可用,称为token。在处理包含特定引号的参数时,这两种形式非常有用。它对于其他语言或WMIC的REPL接口特别有用。 尽管在这两种情况下,表达式都可以放在双引号中,仍然会被处理

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

@echo off


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

要在同一个块中使用指定的变量,也要检查< >强推迟扩张< / >强 . 0块

还有一些技巧

为了避免为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也可以很好地用于< >强管道< / >强,它可以用于链接命令(尽管它不太适合分配变量。

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%

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

这里,我的变量名是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