输出变量上的 CMD 子字符串提取

Posted

技术标签:

【中文标题】输出变量上的 CMD 子字符串提取【英文标题】:CMD Substring Extraction On Output Variable 【发布时间】:2020-11-29 03:28:25 【问题描述】:

寻找有关在批处理脚本中对命令输出的变量执行子字符串提取的指导。具体来说,我使用的命令是powershell (Get-CimInstance Win32_OperatingSystem).version

我已经使用for /f "tokens=*" %%i in ('"powershell (Get-CimInstance Win32_OperatingSystem).version"') do set OSvar=%%i成功设置了这个变量

如您所见,我正在查询操作系统版本,并且我有一个未公开的、半有效的用例用于使用此特定方法来查找它。即使我使用上述方法查询的推理可能会被误导,但我仍然想学习如何对这个输出执行子字符串提取,以供我自己启迪。找到解决方案不如在给定上下文中找到解决方案重要。

显然,这将输出“6.2.9200”、“6.3.9600”或“10.0.XXXXXXX”的效果。我想知道如何在小数点后第二位之前提取输出,但是我在研究后尝试的所有尝试都失败了,包括设置分隔符和使用第二个变量集等于第一个变量集 :~0,3%。这里的大师可以帮助一个人吗?

【问题讨论】:

【参考方案1】:

如果您只需要主要和次要数字,通过powershell,那么只返回那些似乎更明智,而不是事后解析结果:

For /F %%G In ('^""%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" ^
 -NoProfile -NoLogo -Command "[System.Environment]::OSVersion.Version | " ^
 "ForEach-Object  '0.1' -F $_.Major,$_.Minor "^"') Do Set "OSVar=%%G"

作为单行者:

For /F %%G In ('%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP "[System.Environment]::OSVersion.Version|%%'0.1' -F $_.Major,$_.Minor"')Do Set "OSVar=%%G"

如果你真的想坚持使用powershell 和Get-CimInstance

For /F %%G In ('^""%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoP ^
 "(Get-CimInstance Win32_OperatingSystem).Version.Split('.')[0,1] -Join '.'"^"'
) Do Set "OSVar=%%G"

作为单行者:

For /F %%G In ('%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP "(GCim Win32_OperatingSystem).Version.Split('.')[0,1] -Join '.'"')Do Set "OSVar=%%G"

但是,如果您希望在检索到 do 部分后对其进行解析,那么我建议使用比使用标记和分隔符更简单的方法:

For /F %%G In ('^""%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" ^
 -NoProfile -NoLogo "(Get-CimInstance Win32_OperatingSystem).Version"^"'
) Do Set "OSVar=%%~nG"

作为单行者:

For /F %%G In ('%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP "(GCim Win32_OperatingSystem).Version"')Do Set "OSVar=%%~nG"

在前面的两个示例中,.BuildNumber 被视为扩展名,因此使用元变量扩展我们可以返回不带扩展名的名称。


但是,您不需要powershell 来获取 WMI 信息,您可以改用wmic:

For /F %%G In ('"%__AppDir__%wbem\WMIC.exe" OS Get Version'
) Do If "%%~xG" NEq "" Set "OSVar=%%~nG"

再次作为单行者:

For /F %%G In ('%__AppDir__%wbem\WMIC.exe OS Get Version')Do If "%%~xG" NEq "" Set "OSVar=%%~nG"

【讨论】:

OSVersion 的问题在于它在 Windows 8 中已被弃用,并且会产生不一致的结果。我已经看到 Windows 8.1 (6.3.9600) 将自己标识为 Windows 8 (6.2.9200)。使用 CIMInstance 会调用 WinRM,这是查询 this 的推荐方法。 据我记得@JeremyBrown,它在后台使用的方法已被弃用,但该命令仍然按预期工作。请尝试一下,我知道它至少适用于 Windows 10! 它在我尝试过的单台计算机上工作,但我看到它产生了我在另一台机器上描述的错误。微软脚本专家 Ed Wilson 似乎对 Windows 8 和 OSVersion 有同样的印象:devblogs.microsoft.com/scripting/… @JeremyBrown,已弃用意味着在未来的版本中它可能会被删除或不再受支持。我知道它可以在 Windows 10 中运行,并且您已经看到它在 8.1 中运行,您已经证明了我的观点。但是,如果您对使用 Get-CimInstance 以外的任何其他内容不满意,那么我建议您查看我编辑的答案,看看我将如何使用它。 嗯,当我演示 OSVersion 在 Windows 8 上存在限制时,您的意思是“它在 1 台计算机上工作,因此它始终工作”。当您推出脚本时对于成千上万台机器的生产,您不能采取“足够好”的方法。【参考方案2】:

好吧,将结果除以.

@echo off
for /f "tokens=1,2delims=." %%i in ('powershell (Get-CimInstance Win32_OperatingSystem^).version') do (
    set "OSvar=%%i.%%j"
)
echo %OSvar%

或来自同一代码的单行:

@echo off
for /f "tokens=1,2delims=." %%i in ('powershell (Get-CimInstance Win32_OperatingSystem^).version') do echo %%i.%%j

您也可以使用标准的ver 命令;

@for /f "tokens=1-5,*delims=. " %%i in ('ver') do @set OSvar=%%l.%%m

按要求解释。 看到我们用. 分割字符串,每个标记都被分配给一个元变量。换一种说法。假设它是windows 10.0.18362.959,那么tokens=1,2 会将10 分配给%%i,将0 分配给%%j

【讨论】:

这是解决方案,谢谢。出于某种原因,for /f "tokens=1,2,* delims=." 有效,而 tokens=1,2tokens=1,2,3 无效。有人可以向我解释一下吗? 它确实适用于1,2 1,2,3*` 等。我更新了答案以证明它:) 它是元变量的用法。我们将第一个虚线值分配给令牌 1(元变量 %%i),将第二个值分配给令牌 2(元变量 %%j),尽管我们没有为它分配令牌,但您不能使用余数。所以echo %%k 将导致%%k。只有当我们告诉系统之后的所有东西都应该分配给另一个令牌时,它才能使用它。 当然,它现在可以与tokens=1,2 一起使用,尽管我发誓我以前用相同的语法做过。它表明有时您只需要上网并抱怨某件事即可开始工作,但感谢您的解释! 玩转它,设置自己的字符串,看看如何使用令牌来使用各个部分 :) 很高兴你被排序了。 如果我能够留下有意义的投票,我会再次投票给你的答案^^谢谢。【参考方案3】:

希望这是您要提取的内容:

@echo off
@For /f "tokens=1,2,3 delims=." %%a in (
    '"powershell (Get-CimInstance Win32_OperatingSystem).version"'
) Do ( 
    Set "FirstVar=%%a"
    Set "SecondVar=%%b"
    Set "ThirdVar=%%c"
    Set "AllVar=%%a.%%b.%%c
)

echo FirstVar  = %FirstVar%
echo SecondVar = %SecondVar%
echo ThirdVar  = %ThirdVar%
echo AllVar    = %AllVar%
pause

【讨论】:

这会导致输出: %a.%b 在此设置标记和分隔符似乎很棘手,可能是因为它正在管道输出已经有括号的 powershell 命令的输出? UsebackQ 添加到 for 循环选项并将单引号更改为反引号。 TY 到目前为止的建议。我试过这个:for /f "Tokens=1,2,3 delims=. USEBACKQ" %%a in (`"powershell (Get-CimInstance Win32_OperatingSystem).version"`) do (set "OSvar1=%%a" set "OSvar2=%%b" set "OSvar3=%%c" set "OSvar=%%a.%%b.%%c") echo %OSvar% 结果是这样的:%a.%b 即使做echo %%a 也会导致%a "USEBACKQ Tokens=1,2,3 delims=." @T3RR0R,绝对没有理由在这里usebackq

以上是关于输出变量上的 CMD 子字符串提取的主要内容,如果未能解决你的问题,请参考以下文章

在 Bash 中提取子字符串

如何使用递归提取子字符串列表?

java 从一个URL中提取特定子字符串保存

从字符串中提取子字符串

如何从 C++ 中的 getline 函数中提取特定的子字符串?

在文本中的特定字符之前或之后提取的子字符串