在.bat文件中使用PowerShell,将一个字符串替换为多个字符串

在.bat文件中使用PowerShell,将一个字符串替换为多个字符串,powershell,batch-file,replace,windows-10,Powershell,Batch File,Replace,Windows 10,我正在使用.baat将几个文件移动到另一个文件夹中,但在实际移动部分之前,我想替换最后一行(这是已知的一行),例如,我有一个文件output.txt,如下所示: HEADER BODY FOOTER 我期望的回报是 HEADER BODY ONE_MORE_LINE FOOTER 并返回此错误: A cadeia de caracteres não tem o terminador: ". + CategoryInfo : ParserError:

我正在使用.baat将几个文件移动到另一个文件夹中,但在实际移动部分之前,我想替换最后一行(这是已知的一行),例如,我有一个文件output.txt,如下所示:

HEADER BODY FOOTER 我期望的回报是

HEADER BODY ONE_MORE_LINE FOOTER 并返回此错误:

A cadeia de caracteres não tem o terminador: ". + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString 它所做的是使用commant
findstr/v
“FOOTER”我在文件output.sql中查找所有不是FOOTER的行,并将其写入new_output.sql

然后我
TYPE
将其返回到原始文件,并
DEL
新的_output.sql

然后我在它下面回显我需要的所有行


它可以工作,但对于大文件,我认为重新编写两次会花费很多时间,但我无法找到其他解决方案。

处理大文件时,最好使用文件流。更典型的方法是使用批处理
for/f
循环逐行读取文件,或在PowerShell中使用
Get Content
将整个文件读取到内存中,这可能会使处理过程变慢,导致对大文件的爬网。另一方面,使用文件流,您几乎可以立即从文件的末尾返回到最后一行的开头,插入所需的数据,然后重新组合您重写的字节

下面的示例将使用PowerShell对.NET方法的访问来将文件作为字节流打开,以便快速读取和写入。有关详细信息,请参阅内联注释。文件编码有望得到保留。使用.bat扩展名保存此文件,并尝试一下


#构造用于读取和写入$env:file的文件流
$IOstream=新对象IO.FileStream((gi$env:file).FullName,
[IO.FileMode]::打开或创建[IO.FileAccess]::读写)
#读取BOM表以确定文件编码
$reader=新对象IO.StreamReader($IOstream)
[void]$reader.Read((新对象字节[]3),0,3)
$encoding=$reader.CurrentEncoding
$reader.DiscardBufferedData()
#将要插入的行转换为文件的本机编码
$utf8line=[Text.Encoding]::UTF8.GetBytes(`r`n$env:line”)
$line=[Text.Encoding]::转换([Text.Encoding]::UTF8,$Encoding,$utf8line)
$charSize=[math]::天花板($line.length/$utf8line.length)
#将指针移到流的末尾
$pos=$IOstream.Seek(0,[IO.SeekOrigin]::End)
#当流不返回错误时返回指针
而($char-gt-1){
$IOstream.Position=--$pos
$char=$reader.Peek()
$reader.DiscardBufferedData()
#找到非空白前的换行符时中断循环
if($foundPrintable){if($char-eq 10){break}
else{if([char]$char-match“\S”){$foundPrintable++}
}
#将指针移回回车,并读取到$buffer中,前面加了$line
$pos-=$charSize
$IOstream.Position=$pos
$buffer=$encoding.GetBytes($encoding.GetString($line)+$reader.ReadToEnd())
$IOStream.Position=$pos
“在字节$pos插入数据”
$IOstream.Write($buffer,0,$buffer.Length)
#垃圾收集
$reader.Dispose()
$IOstream.Dispose()

这种方法应该比从一开始就读取文件,或者将整个文件复制到内存或插入新行的磁盘上更有效。在我的测试中,它会在大约1/3秒内将行插入到一个100兆的文件中。

处理大文件时,最好使用文件流。更典型的方法是使用批处理
for/f
循环逐行读取文件,或在PowerShell中使用
Get Content
将整个文件读取到内存中,这可能会使处理过程变慢,导致对大文件的爬网。另一方面,使用文件流,您几乎可以立即从文件的末尾返回到最后一行的开头,插入所需的数据,然后重新组合您重写的字节

下面的示例将使用PowerShell对.NET方法的访问来将文件作为字节流打开,以便快速读取和写入。有关详细信息,请参阅内联注释。文件编码有望得到保留。使用.bat扩展名保存此文件,并尝试一下


#构造用于读取和写入$env:file的文件流
$IOstream=新对象IO.FileStream((gi$env:file).FullName,
[IO.FileMode]::打开或创建[IO.FileAccess]::读写)
#读取BOM表以确定文件编码
$reader=新对象IO.StreamReader($IOstream)
[void]$reader.Read((新对象字节[]3),0,3)
$encoding=$reader.CurrentEncoding
$reader.DiscardBufferedData()
#将要插入的行转换为文件的本机编码
$utf8line=[Text.Encoding]::UTF8.GetBytes(`r`n$env:line”)
$line=[Text.Encoding]::转换([Text.Encoding]::UTF8,$Encoding,$utf8line)
$charSize=[math]::天花板($line.length/$utf8line.length)
#将指针移到流的末尾
$pos=$IOstream.Seek(0,[IO.SeekOrigin]::End)
#当流不返回错误时返回指针
而($char-gt-1){
$IOstream.Position=--$pos
$char=$reader.Peek()
$reader.DiscardBufferedData()
#找到非空白前的换行符时中断循环
if($foundPrintable){if($char-eq 10){break}
else{if([char]$char-match“\S”){$foundPrintable++}
}
#将指针移回回车,并读取到$buffer中,前面加了$line
$pos-=$charSize
$IOstream.Position=$pos
$buffer=$encoding.GetBytes($encoding.GetString($line)+$reader.ReadToEnd())
$IOStream.Position=$pos
“在字节$pos插入数据”
$IOstream.Write($buffer,0,$buffer.Length)
#垃圾收集
$reader.Dispose()
$IOstream.Dispose()

这种方法应该比从一开始就读取文件,或者将整个文件复制到内存或插入新行的磁盘上更有效。在我的测试中,它会在大约1/3秒内将该行插入一个100兆文件。

PowerShell不会在单引号字符串中展开转义序列。这里必须使用双引号字符串。将嵌套的双引号加倍以对CMD:
po进行转义
HEADER
    BODY
 ONE_MORE_LINE `r`n FOOTER
powershell -Command "(gc output.txt) -replace 'FOOTER;', ""ONE_MORE_LINE `r`n FOOTER"" | Out-File output.txt "
A cadeia de caracteres não tem o terminador: ". + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
findstr /v "FOOTER" output.sql > new_output.sql
TYPE new_output.sql > output.sql
del new_output.sql
ECHO. >> %%f
ECHO ONE_MORE_LINE >> %%f
ECHO FOOTER >> %%f
ECHO. >> %%f