简体   繁体   English

如何使用 PowerShell 替换文件中的一行?

[英]How do I replace a line in a file using PowerShell?

I am trying to read replace a line in a configuration file using PowerShell.我正在尝试使用 PowerShell 读取替换配置文件中的一行。 Sometimes this script works, but most of the time it does not replace the line.有时此脚本有效,但大多数情况下它不会替换该行。

(Get-Content D:\home\App_Config\Sitecore.config) `
    | %{ $_ -replace '  <setting name="Media.MediaLinkServerUrl" value=" "/>',' <setting name="Media.MediaLinkServerUrl" value="https://newurl.com"/>'} `
    | Set-Content D:\home\App_Config\Sitecore.config

Try the following:请尝试以下操作:

$file = 'D:\home\App_Config\Sitecore.config'
$regex = '(?<=<setting name="Media\.MediaLinkServerUrl" value=")[^"]*'
(Get-Content $file) -replace $regex, 'https://newurl.com' | Set-Content $file

* Re Set-Content : In Windows PowerShell it uses your system's legacy single-byte character encoding by default (based on the active ANSI code page), so you may want to use -Encoding to control the output file's encoding explicitly; * 重新Set-Content :在Windows PowerShell 中,它默认使用您系统的旧单字节字符编码(基于活动的 ANSI 代码页),因此您可能希望使用-Encoding显式控制输出文件的编码; PowerShell [Core] 6+ defaults to BOM-less UTF-8. PowerShell [Core] 6+默认为无 BOM 的 UTF-8。

  • Also note the required (...) around the Get-Content call to ensure that the pipeline can write back to the same file that Get-Content has read from.还要注意Get-Content调用周围的必需(...) ,以确保管道可以写回Get-Content已从中读取的同一文件。
  • If there's a chance that the opening tag in question ( <setting ...> ) spans multiple lines , use如果有问题的开始标记( <setting ...> )有可能跨越多行,请使用
    Get-Content -Raw $file (PSv3+) to read the entire file content as a single string (thanks, deadlydog ); Get-Content -Raw $file (PSv3+) 将整个文件内容作为单个字符串读取(谢谢, deadlydog );
    without -Raw , Get-Content returns an array of strings, representing the input lines .没有-RawGet-Content返回一个字符串数组,表示输入

Due to using a regular expression to match your existing setting, any text currently inside value="..." is matched, so this command will work even when run repeatedly .由于使用正则表达式来匹配您现有的设置,当前在value="..."任何文本都会匹配,因此即使重复运行此命令也能正常工作。

By contrast, what you tried uses an effective literal ( ... value=" " ) to find what to replace, and after the 1st - successful - run, that literal no longer matches, and subsequent runs have no effect.相比之下,您尝试使用有效文字( ... value=" " ) 来查找要替换的内容,并且在第一次成功运行后,该文字不再匹配,后续运行无效。

The command above uses a streamlined approach to replacement:上面的命令使用了一种简化的替换方法:

  • (?<=<setting name="Media.MediaLinkServerUrl" value=") is a look-behind assertion ( (?<=...) ) that matches, but doesn't capture what it matches: it finds the part up to and including the opening " of the value you're trying to replaces, without making that prefix a part of what will get replaced. (?<=<setting name="Media.MediaLinkServerUrl" value=")是匹配的后视断言( (?<=...) ),但不捕获它匹配的内容:它找到了部分到并包括您要替换的值的开头" ,而不将该前缀作为将被替换的内容的一部分。

  • [^"]* then matches the entire value, up to, but not including the closing " . [^"]*然后匹配整个值,直到但不包括结束的" ( [^"] is a character set that matches any character other than ( ^ ) a " , and * finds any (possibly empty) sequence of such characters. [^"]是比其他任何字符相匹配的字符集( ^ )一个" ,和*找到这样任何字符(可能是空的)序列。

  • Therefore, because the regex captured only the value itself, all you need to specify as the replacement string is the new value.因此,由于正则表达式仅捕获值本身,因此您需要指定的替换字符串就是新值。

Use the Replace method like this:像这样使用 Replace 方法:

$file = 'D:\home\App_Config\Sitecore.config'
$find = '  <setting name="Media.MediaLinkServerUrl" value=" "/>'
$replace = ' <setting name="Media.MediaLinkServerUrl" value="https://newurl.com"/>'

(Get-Content $file).replace($find, $replace) | Set-Content $file

This Function worked for me这个功能对我有用

I am trying to replace anything come after Infile我正在尝试替换 Infile 之后的任何内容在此处输入图片说明

Function:功能:

function Write-FileContent {
        [cmdletBinding()]
        param(
            [parameter(Mandatory = $true)]
            [string]$FileToReplacePath,
            [parameter(Mandatory = $true)]
            [string]$TextToReplaceWith,
            [parameter(Mandatory = $true)]
            [string]$LineNumber,
            [parameter(Mandatory = $true)]
            [string]$TextToBeingWith        
        )
        $Read = Get-Content -Path $FileToReplacePath
        $Read | ForEach-Object { if ($_.ReadCount -eq $LineNumber) { $_ -replace "'$TextToBeginWith'=.+'", "$TextToReplaceWith" }   else { $_ } } | Set-Content $FileToReplacePath
    }

Testing Parameter测试参数

$CsvFilePath="C:\msydatfgdfa.csv"
Write-FileContent -FileToReplacePath D:\test.txt -TextToReplaceWith "'$CsvFilePath'" -LineNumber 2 -TextToBeingWith "Infile"

Here's an example that preserves the PSPath property, so you don't have to specify the path to set-content:这是一个保留 PSPath 属性的示例,因此您不必指定 set-content 的路径:

(Get-Content -raw input) | ForEach-Object {
    $_ -replace 111,222 |
    Add-Member NoteProperty PSPath $_.PSPath -PassThru
} | Set-Content -nonewline

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM