在批处理文件中捕获PowerShell命令的输出';s/f循环

在批处理文件中捕获PowerShell命令的输出';s/f循环,powershell,batch-file,for-loop,cmd,syntax,Powershell,Batch File,For Loop,Cmd,Syntax,此PowerShell代码从此字符串中为var5选择正确的值。它“发出警报”的预期结果 但是,在cmd shell脚本中使用相同的powershell代码会产生不同的结果。为什么呢?cmd shell是否需要转义某些内容 C:>type mat002-annex.bat @ECHO OFF SET "S=Status 58 var5=Alert Raised on: March" ECHO S is set to %S FOR /F %%a IN ('powershell -NoLog

此PowerShell代码从此字符串中为
var5
选择正确的值。它“发出警报”的预期结果

但是,在cmd shell脚本中使用相同的powershell代码会产生不同的结果。为什么呢?cmd shell是否需要转义某些内容

C:>type mat002-annex.bat
@ECHO OFF
SET "S=Status 58   var5=Alert Raised on: March"
ECHO S is set to %S
FOR /F %%a IN ('powershell -NoLogo -NoProfile -Command ^
    " '%S%' | Where-Object { $_ -match '.*var5=(.*)\s+\w+:' } | ForEach-Object { $Matches[1] } "') DO (ECHO Result is "%%a")

C:>mat002-annex.bat
S is set to S
Result is "Alert"

批处理文件中不需要
for
循环

@ECHO OFF
SET "S=Status 58   var5=Alert Raised on: March"
powershell -NoLogo -NoProfile -Command " '%S%' | Where-Object { $_ -match '.*var5=(.*)\s+\w+:' } | ForEach-Object { $Matches[1] } "
上面给出了预期的结果。

正如他经常做的那样,在评论中提供了关键的指针:

cmd.exe
for/f
循环默认情况下会将其输入行按空格分隔成标记
,以便
for/f%%a in(…)do
只将第一个这样的标记放在变量
%%a

可以使用选项字符串修改此默认行为:
用于(…)do中的/f”“%%a

cmd.exe
提示符运行
for/?
,说明其语法:

    eol=c           - specifies an end of line comment character
                      (just one)
    skip=n          - specifies the number of lines to skip at the
                      beginning of the file.
    delims=xxx      - specifies a delimiter set.  This replaces the
                      default delimiter set of space and tab.
    tokens=x,y,m-n  - specifies which tokens from each line are to
                      be passed to the for body for each iteration.
                      This will cause additional variable names to
                      be allocated.  The m-n form is a range,
                      specifying the mth through the nth tokens.  If
                      the last character in the tokens= string is an
                      asterisk, then an additional variable is
                      allocated and receives the remaining text on
                      the line after the last token parsed.
    usebackq        - specifies that the new semantics are in force,
                      where a back quoted string is executed as a
                      command and a single quoted string is a
                      literal string command and allows the use of
                      double quotes to quote file names in
                      file-set.

如果希望在单个变量中捕获每个输入行,则有两个选项: 注意:下面的示例使用下面的PowerShell命令行,该命令行只输出一个包含多个前导、内部和尾随空格的字符串文本,
one-two

powershell -command " '   one   two   ' "
为了简化报价,下面使用了选项
usebackq
,它允许将命令嵌入
`…`

还要注意的是,将
-NoProfile
添加到
powershell.exe
的命令行是一种很好的做法,以防止不必要的、可能会改变行为的用户配置文件加载;为了简洁起见,我在下面省略了它


“delims=”
:按原样保留行 上述收益率:

Result is "   one   two   "
Result is "one   two   "
请注意,前导空格和尾随空格也是如何保留的

重要:要将
delims=
识别为停用基于分隔符(基于分隔符)的解析,必须将其置于选项字符串的最末尾。


“tokens=*”
:修剪前导空格 上述收益率:

Result is "   one   two   "
Result is "one   two   "
请注意前导空格是如何修剪的


奇怪的是,修剪只应用于前导空格,而且似乎没有直接的方法来修剪尾随空格。

for/?
:默认情况下,
/F
从每个文件的每一行传递第一个空格分隔的标记。@PetSerAl-是。完全正确我需要“代币=*”。为什么?省去批处理文件,直接使用PowerShell。PowerShell已经提供了10多年,并且自Windows 7以来一直是操作系统的内置部分。做开关;“这是值得投资的。”比尔·斯图尔特——我已经相信了。我不是做出这样决定的人。我会尽我所能。2012年前一个月发布的PowerShell 3是可行的。也许你的说法应该是它在五(5)年前是可用的。你是对的,这确实为stdout提供了正确的输出。我仍然需要做些什么才能把它变成一个变量。PetSerAl发现了它。鉴于(正如我们现在更清楚地知道的)意图是在变量中catpure PowerShell的输出,我可以建议您修改或删除您的答案吗?顺便说一句:虽然使用
-NoProfile
是一种良好的做法,但将
-NoLogo
-Command
-File
结合使用是不必要的。
Result is "one   two   "