我遇到了从文件中提取文本的问题。以下是我最终想要做的:
- 在特定文件中搜索短语"NoRequest"的实例。
- 仅取 NoRequest 的值,即如果 NoRequest = true,则只会将"true"添加到数组中,而不是整行。
- 对文件中短语的每个实例执行此操作。
以下是我正在处理的部分的片段:
$FileContents = Select-String -Path "C:UsersmeDocumentsfile.ini" -Pattern "NoRequest"
当我使用该行时,我得到以下内容:
PS> $FileContents 文档\文件.ini:222:无请求 = 假 文档\文件.ini:281:否请求 = 假 文档\文件.ini:347:无请求 = 假 文档\文件.ini:387:无请求 = 假 文档\文件.ini:1035:NOREQUEST = true 文档\文件.ini:1047:否请求 = 真 文档\文件.ini:1160:NOREQUEST = true 文档\文件.ini:1242:NOREQUEST = true
这就是我想要得到的:
PS> $FileContents 假 假 假 假 真 真 真 确实
,我已经尝试将代码管道到Select-Object -Last 1
解决方案中,但由于我的变量是一个数组,因此它选择数组中的最后一行,而不是每行的最后一行。我还想过只是拿起数组并做一个"数组中的每行,切断除最后一个单词之外的所有内容"。我猜这会起作用,但这似乎是一个笨拙的解决方案。我确信有一个简单有效的解决方案,但我只是没有看到它。
您可以在字符串上使用-split
并获取最后一个结果:
Select-String -Path "C:UsersmeDocumentsfile.ini" -Pattern "NoRequest" |ForEach-Object {
-split $_.Line |Select-Object -Last 1
}
或者,您可以直接读取文件,将其传递给Where
语句以查找所需的行,然后使用$Matches
自动变量。
$FileContents = Get-Content "C:UsersmeDocumentsfile.ini" |
Where{$_ -Match 'NoRequest = (true|false)'} |
ForEach-Object { $Matches[1] }
对于小文件(如*.ini
文件(,可以选择使用表达式而不是管道,这样可以实现既简洁又高性能的解决方案(PSv4+ 语法(:
(@(Get-content C:UsersmeDocumentsfile.ini) -match 'NoRequest').ForEach({ (-split $_)[-1] })
@(Get-content C:UsersmeDocumentsfile.ini)
将指定文件的行作为数组返回(@(...)
确保即使文件中恰好只有1行,也返回数组(。-match
,以数组作为 LHS,充当过滤器,仅返回与指定正则表达式匹配的元素。然后,PSv4+
.ForEach()
方法作用于结果数组的元素,通过空格 (-split
( 将每个元素拆分为标记,并返回最后一个标记 (-1
(。
顺便说一句:-split
运算符(-split '...'
(的一元形式就像Unix实用程序默认的古老awk
:标记是根据任何非空的空格作为分隔符提取的,前导和尾随空格被忽略。
将正则表达式更改为(?<=NoRequest.* )(w+)$
,以便它与行中的最后一个单词(w+
是一个或多个单词字符,$
行尾(匹配,前提是它前面有字符串"NoRequest"。(?<=...)
是一个积极的后视断言,用于检查模式是否存在,而不使其成为返回的匹配项的一部分。然后展开匹配项的值。
$file = 'C:UsersmeDocumentsfile.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
}