【问题标题】:Taking the last word of each line from Select-String从 Select-String 中取出每一行的最后一个单词
【发布时间】:2019-01-28 01:17:18
【问题描述】:

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

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

这是我正在处理的部分的 sn-p:

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

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

PS> $文件内容 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> $文件内容 错误的 错误的 错误的 错误的 真的 真的 真的 真的

我尝试将代码导入Select-Object -Last 1 解决方案,但由于我的变量是一个数组,它选择数组中的最后一行,而不是每行的最后一个单词。我还想过只取数组并做一个“数组中的 foreach 行,除最后一个单词之外的所有内容”。我猜这会起作用,但它似乎是一个笨拙的解决方案。我确信有一个简单有效的解决方案,但我只是没有看到它。

【问题讨论】:

    标签: arrays powershell variables foreach select-string


    【解决方案1】:

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

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

    【讨论】:

    • 我一直很喜欢ForEach-Object { $_.Line.Trim().Split(' ')[-1] }的方法。我认为有些人对循环中的嵌入式管道感到困惑,并且不知道他们正在处理什么管道。
    • 这不是很明显,但这是awk 默认所做的,也许这就是 PowerShell 选择的模型。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      • -match,以 array 作为 LHS,充当 过滤器 并仅返回与指定正则表达式匹配的元素。

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

      顺便说一句:-split operator (-split '...') 的 一元 形式的行为类似于可敬的 awk Unix utility 默认情况下:根据任何非空的空白运行提取令牌作为分隔符,忽略前导和尾随空格。

      【讨论】:

        【解决方案4】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-25
          • 1970-01-01
          • 2012-03-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多