在 for-each 循环中使用 select-string

3

我正在构建一个脚本,它可以访问大量文件并提取特定的字符串以便分配为变量。

这个字符串在所有文件中都很相似,所以这不是问题。我可以将此过程作为单独事件运行(定义单一源文件)。

$hostname_import = select-string .\test.txt -Pattern 'hostname ABC-.+'
$hostname = $hostname_import -replace '.+ ',''

上述代码将输出目标文件中特定的主机名(第二个函数是裁剪字符串"hostname"和空格),我可以使用该变量按需执行各种操作。
我的问题在于如何在foreach循环中执行此函数,以便我可以获取初始文件,执行select-string函数(或类似函数),并在循环中按预期执行数据修改。
为了背景说明,我正在查看配置文件,并基于这些配置构建一个单独的文件以报告发现情况。报告构建的一部分要求获取设备的主机名。
--编辑1: 经过与我的小黄鸭协商后,我将尝试将这些文件作为CSV导入,以便可能达到解决方案。
感谢@Otter帮助我解决问题。我之前有一个脚本使用了这个函数,但由于某些原因,我无法像预期的那样执行该函数。这个脚本与我的上一个脚本的不同之处在于$_.Fullname。非常有帮助!
2个回答

6

Select-String 可以通过 -Path-LiteralPath 参数直接处理一个文件数组或通配符表达式来处理多个文件。

它不支持传递目录路径来处理其中的文件(更不用说递归了),因此,你需要将 Get-ChildItem (可能带有 -Recurse)返回的结果传递给 Select-String 命令。

下面的示例展示了使用后者技术,循环遍历当前目录子树中的所有 *.config 文件:

Get-ChildItem -File -Recurse -Filter *.config |
  Select-String -Pattern 'hostname ABC-(.+)' |
   ForEach-Object {
     $sourceFilePath = $_.Path
     $hostName = $_.Matches[0].Groups[1].Value
   }

注意在正则表达式模式中使用了捕获组 ((...)),它允许通过 Select-String 输出的 Microsoft.PowerShell.Commands.MatchInfo 实例,仅提取感兴趣的子字符串,从而避免了使用 -replace 操作;详情请参见底部章节。
请注意,每个文件可能报告 多个 匹配项;如果您知道只有 一个 匹配项(或者只对 第一个 匹配项感兴趣),请在 Select-String 调用中添加 -List 以加快操作速度。
如何仅提取匹配行/行部分的 文本 (字符串): 当您直接在字符串上下文中使用 Select-String 输出对象(类型为 Microsoft.PowerShell.Commands.MatchInfo)例如在 -replace 中时,如果已给出文件参数,则生成的字符串表示形式包含比仅仅是匹配的行文本更多内容,因为输入文件路径会被添加到行文本之前,后跟 :;例如:
C:\path\to\file.config:hostname ABC-foo 要直接作为字符串提取 仅行文本,请使用 .Line 属性
注意:在 PowerShell (Core) 7+ 中,您现在可以通过传递 -Raw 开关要求 Select-String 直接输出字符串(匹配行)。
要仅提取正则表达式匹配的行的一部分,请使用 .Matches 属性(如果也传递了用于字面子串匹配的 -SimpleMatch 开关,则不适用),如上所示。
  • .Matches 是一个 System.Text.RegularExpressions.Match 实例的集合(如果传递了 -AllMatches 开关,则可能有多个元素),每个实例的 .Value 属性包含整个模式匹配的文本

  • 如果 -Pattern 表达式包含捕获组(...)),则每个Match 实例的 .Groups 集合 - 由Match 实例组成 - 包含这些组所捕获的内容,从索引1开始;同样,.Value 属性包含捕获到的文本


1

看起来你需要一个Get-ChildItem,它将获取文件夹中的所有文件,然后将输出传递到Foreach-Object循环中,该循环将引用每个文件。

请注意,我已添加了-recurse开关,以防需要获取子文件夹文件。

尝试以下操作:

Get-Childitem -path "C:\PathToFolder" -recurse | Foreach-Object {
    $hostname_import = select-string $_.Fullname -Pattern 'hostname ABC-.+'
    $hostname = $hostname_import -replace '.+ ',''
    
    # The rest of your logic goes here
}

2
这个方法是可行的,但是每个输入文件都调用一次 Select-String 是低效的。最好将 Get-ChildItem 的输出直接传递到 Select-String 中。此外,为了仅操作匹配行的文本,请使用 $hostname_import.Line - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接