从 Select-String 中取出每行的最后一个单词

Taking the last word of each line from Select-String

我在从文件中提取文本时遇到问题。这是我最终想做的:

  1. 在特定文件中搜索短语 "NoRequest" 的实例。
  2. 只取NoRequest的值。即如果 NoRequest = true,那么它只会将 "true" 添加到数组,而不是整行。
  3. 对文件中的每个短语实例执行此操作。

这是我正在处理的部分的片段:

$FileContents = Select-String -Path "C:\Users\me\Documents\file.ini" -Pattern "NoRequest"

当我使用那条线时,我得到以下信息:

PS> $FileContents
Documents\file.ini:222:NoRequest = false
Documents\file.ini:281:NoRequest = false
Documents\file.ini:347:NoRequest = false
Documents\file.ini:387:NoRequest = false
Documents\file.ini:1035:NOREQUEST = true
Documents\file.ini:1047:NoRequest = true
Documents\file.ini:1160:NOREQUEST = true
Documents\file.ini:1242:NOREQUEST = true

这是我想要得到的:

PS> $FileContents
false
false
false
false
true
true
true
true

我已经尝试将代码导入 Select-Object -Last 1 解决方案,但由于我的变量是一个数组,它选择了数组中的最后一行,而不是每行的最后一个单词。我还考虑过只获取数组并执行 "foreach line in the array, cut everything off except the last word"。我猜这会起作用,但它似乎是一个笨拙的解决方案。我确信有一个简单有效的解决方案,但我只是没有看到它。

您可以在字符串上使用 -split 并获取最后的结果:

Select-String -Path "C:\Users\me\Documents\file.ini" -Pattern "NoRequest" |ForEach-Object {
    -split $_.Line |Select-Object -Last 1
}

或者,您可以只读入文件,将其传递给 Where 语句以查找所需的行,然后使用 $Matches 自动变量。

$FileContents = Get-Content "C:\Users\me\Documents\file.ini" | 
    Where{$_ -Match 'NoRequest = (true|false)'} | 
    ForEach-Object { $Matches[1] }

对于 *.ini 文件之类的小文件,使用 表达式 而不是管道是一种选择,它可以实现既简洁又高效的解决方案(PSv4+ 语法):

(@(Get-content C:\Users\me\Documents\file.ini) -match 'NoRequest').ForEach({ (-split $_)[-1] })
  • @(Get-content C:\Users\me\Documents\file.ini) returns 将指定文件的行作为一个数组(@(...)确保返回一个数组,即使碰巧只有 1 文件中的行).

  • -match,以 array 作为 LHS,充当 filter 和 returns 仅匹配指定正则表达式的那些元素。

  • PSv4+ .ForEach() 方法然后作用于结果数组的元素,通过空格将每个元素分成标记(-split ),并返回 last 标记 (-1).

顺便说一句:-split operator (-split '...') acts like the venerable awk Unix utility 一元 形式默认执行:基于任何非空的 运行 空格作为分隔符来提取标记, 前导和尾随空格被忽略。

将您的正则表达式更改为 (?<=NoRequest.* )(\w+)$,以便它匹配一行中的最后一个单词(\w+ 是一个或多个单词字符,$ 是一行的结尾) 仅当它前面有字符串 "NoRequest" 时。 (?<=...) 是一个积极的回顾断言,它检查模式的存在而不使其成为返回匹配的一部分。然后展开匹配的值。

$file = 'C:\Users\me\Documents\file.ini'
Select-String -Path $file -Pattern '(?<=NoRequest.* )(\w+)$' | ForEach-Object {
    $_.Matches.Value
}

如果最后一个词只能是 "true" 或 "false",您可以通过将 \w+ 替换为替代词来使表达式更具体:

Select-String -Path $file -Pattern '(?<=NoRequest.* )(true|false)$' | ForEach-Object {
    $_.Matches.Value
}