如何替换文本文件中出现的特定单词

How to replace a single occurrence of a specific word in a text file

我有一个 configuration.txt 文件,我的脚本使用它来填充脚本中的变量。 Tex 文件内容如下:

Setting1= Yes
Setting2= Yes
Setting3= Yes

然后我这样填充我的变量(只拉是或否):

$Setting1=(Get-Content -Path .\configuration.txt | Where-Object {$_ -match 'Setting1='})
$Setting1=($Setting1 -Split '=', 2)[1].trim()

$Setting2=(Get-Content -Path .\configuration.txt | Where-Object {$_ -match 'Setting2='})
$Setting2=($Setting2 -Split '=', 2)[1].trim()

$Setting3=(Get-Content -Path .\configuration.txt | Where-Object {$_ -match 'Setting3='})
$Setting3=($Setting3 -Split '=', 2)[1].trim()

然后我有一些逻辑,如果用户通过我脚本中的提示更改这些设置,脚本会使用以下代码更新文本文件:

((Get-Content -Path .\configuration.txt -Raw | Where-Object {$_ -match 'Setting1'}) -replace $Setting1, $UserSetting1) | Set-Content -Path .\configuration.txt

其中 $UserSetting1 是用户的输入('yes' 或 'no')。

现在所做的是更改配置文件中的每个 'yes' 或 'no' 而不是仅更改我所在的特定行上的 'yes' 或 'no'尝试用匹配功能拉出来

换句话说,如果用户想要将设置 1 更改为 'no' 并将设置 2 和 3 保留为 'yes';脚本正在将所有设置更改为是,而不仅仅是设置 1。

我的印象是我必须使用 -Raw 才能执行 -replace,但如上所述,-match 函数似乎不适用于 -Raw 函数......并且如果我不使用 -raw,那么我的配置文件将只用我匹配的一行重新编写。

您可以直接使用 Replace Operator 进行更新。

$UserSetting1 = 'No'
(Get-Content -Path .\configuration.txt) -replace '(?<=Setting1=).*',$UserSetting1 |
    Set-Content

由于 -replace 使用正则表达式匹配机制,您可以构建仅 return 要替换的数据的匹配。替换字符串可以是一个变量。请参阅下面的正则表达式解释。它匹配 Setting1= 之后一行的剩余字符,然后用存储在 $UserSetting1 中的值替换这些字符。没有匹配项的行将 return 原样编辑,不进行替换。

  • (?<=) 是正则表达式正向回顾断言。它断言在字符串中的给定位置后面有一个完全匹配项。
  • Setting1= 字符串 Setting1=.
  • 的文字匹配
  • .* 尽可能多的字符直到字符串结尾(就在换行符之前)[1].

使用 -Raw 开关将文件内容作为单个字符串读取。如果您对具有匹配项的单个字符串执行正则表达式匹配 (-match),则 $true 被 returned。整个字符串被视为一个匹配项,默认为捕获组 0。$matches[0] 包含该匹配项。因此,如果您使用 -replace 替换该匹配项中的子字符串,它将替换满足 -replace 匹配条件的该子字符串的 每个 实例。

如果不使用-Raw 开关,则文件内容作为行数组读入。 -replace 单独仍然会替换匹配项的每个实例。但是,您现在可以使用 -matchWhere-Object 为某些匹配的行执行不同的代码。

在没有 -Raw 的情况下组合 -match-replace 可能只会导致读取数据的一个子集。当您处理文件的每一行时,-match 将在您处理任何替换之前 return $true 实质上过滤掉任何行。这种情况适合 return 替换,但在您尝试重写整个文件时可能会导致问题。您将需要额外的逻辑来跟踪您已经修改和未修改的数组元素,并在您更新内容时适当地输出它们。


[1] . 如果正则表达式模式是单行,则可以 匹配换行符。您可以在 -replace 正则表达式中以 (?s).

开头启用此模式

另一种方法是读取配置文件并将 name/value 对存储在哈希表中。

如果设置在文本文件中的显示顺序不重要,您可以使用 ConvertFrom-StringData cmdlet。 这将解析设置名称和值,并将其 returns 作为哈希表。

$config = Get-Content -Path .\configuration.txt -Raw | ConvertFrom-StringData

如果顺序 确实 重要,请创建一个有序哈希(需要 PowerShell 3.0 或更高版本):

$config  = [ordered]@{}
Get-Content -Path D:\configuration.txt | ForEach-Object {
    $name, $value = ($_ -split '=' , 2).Trim()
    $config[$name] = $value
}

如果用户想要将 Setting1 的值更改为 no 例如($UserSetting1='no'),只需执行:

$UserSetting1 = 'no'
$config.Setting1 = $UserSetting1

# Next save the updated settings back to the textfile
$newContent = foreach($name in $config.Keys) {
    '{0} = {1}' -f $name, $config.$name
}
$newContent | Set-Content -Path .\configuration.txt -Force