编者注:根据OP后来的评论来判断,这个问题的要点是:如何将一个带有CRLF(Windows风格)行结尾的文件转换为PowerShell中的LF-only(Unix风格)文件?
这是我的powershell脚本:
$original_file ='C:\Users\abc\Desktop\File\abc.txt'
(Get-Content $original_file) | Foreach-Object {
$_ -replace "'", "2"`
-replace '2', '3'`
-replace '1', '7'`
-replace '9', ''`
-replace "`r`n",'`n'
} | Set-Content "C:\Users\abc\Desktop\File\abc.txt" -Force
使用此代码,我可以将3替换为2,使用空字符串替换为7和9。我只能使用换行符替换回车换行符。但这不起作用。
你还没有指定版本,我假设你使用的是Powershell v3。
试试这个:
$path = "C:\Users\abc\Desktop\File\abc.txt"
(Get-Content $path -Raw).Replace("`r`n","`n") | Set-Content $path -Force
编者注:正如迈克在评论中指出的那样,Set-Content
附加了一个尾随的CRLF,这是不受欢迎的。验证:'hi' > t.txt; (Get-Content -Raw t.txt).Replace("`r`n","`n") | Set-Content t.txt; (Get-Content -Raw t.txt).EndsWith("`r`n")
,产生$True
。
请注意,这会将整个文件加载到内存中,因此如果要处理大文件,可能需要不同的解决方案。
UPDATE
这可能适用于v2(抱歉无处测试):
$in = "C:\Users\abc\Desktop\File\abc.txt"
$out = "C:\Users\abc\Desktop\File\abc-out.txt"
(Get-Content $in) -join "`n" > $out
编者注:请注意,此解决方案(现在)写入不同的文件,因此不等同于(仍有缺陷的)v3解决方案。 (一个不同的文件的目标是避免陷阱,Ansgar Wiechers在评论中指出:使用>
在执行开始之前截断目标文件)。但更重要的是:这个解决方案也附加了一个尾随的CRLF,这是不受欢迎的。用'hi' > t.txt; (Get-Content t.txt) -join "`n" > t.NEW.txt; [io.file]::ReadAllText((Convert-Path t.NEW.txt)).endswith("`r`n")
验证,产生$True
。
关于被加载到内存的相同保留。
从Windows PowerShell v5.1 / PowerShell Core v6.2.0开始,这是一个联合状态的答案:
Convert-TextFile
参数的-LineEnding
cmdlet允许使用特定的换行符样式就地更新文本文件,如on GitHub所述。在PSv5 +中,现在可以使用PowerShell原生解决方案,因为Set-Content
现在支持-NoNewline
开关,可以防止对平台原生换行的不希望的附加[1]:
# Convert CRLFs to LFs only.
# Note:
# * (...) around Get-Content ensures that $file is read *in full*
# up front, so that it is possible to write back the transformed content
# to the same file.
# * + "`n" ensures that the file has a *trailing LF*, which Unix platforms
# expect.
((Get-Content $file) -join "`n") + "`n" | Set-Content -NoNewline $file
以上内容依赖于Get-Content
读取文本文件的能力,该文本文件逐行使用CR-only,CRLF和LF-only新行的任意组合。
注意事项:
-Encoding
;没有-Encoding
:
在Windows PowerShell中,您将获得“ANSI”编码,即系统的单字节,8位传统编码,例如美英系统上的Windows-1252。
在PowerShell Core中,您将获得没有BOM的UTF-8编码。[1]事实上,如果要写多个字符串,-NoNewline
也不会在它们之间添加换行符;然而,在这种情况下,这是无关紧要的,因为只写了一个字符串。
替代解决方案,不会附加虚假的CR-LF:
$original_file ='C:\Users\abc\Desktop\File\abc.txt'
$text = [IO.File]::ReadAllText($original_file) -replace "`r`n", "`n"
[IO.File]::WriteAllText($original_file, $text)
基于上面的示例添加另一个版本@ ricky89和@ mklement0几乎没有改进:
要处理的脚本:
LF至CRLF.ps1:
# get current dir
$currentDirectory = Split-Path $MyInvocation.MyCommand.Path -Parent
# create subdir CR-to-CRLF for new files
$outDir = $(Join-Path $currentDirectory "CR-to-CRLF")
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
# get all .txt files
Get-ChildItem $currentDirectory -Force | Where-Object {$_.extension -eq ".txt"} | ForEach-Object {
$file = New-Object System.IO.StreamReader -Arg $_.FullName
# Resulting file will be in CR-to-CRLF subdir
$outstream = [System.IO.StreamWriter] $(Join-Path $outDir $($_.BaseName + $_.Extension))
$count = 0
# read line by line, replace CR with CRLF in each by saving it with $outstream.WriteLine
while ($line = $file.ReadLine()) {
$count += 1
$outstream.WriteLine($line)
}
$file.close()
$outstream.close()
Write-Host ("$_`: " + $count + ' lines processed.')
}
以下将能够快速处理非常大的文件。
$file = New-Object System.IO.StreamReader -Arg "file1.txt"
$outstream = [System.IO.StreamWriter] "file2.txt"
$count = 0
while ($line = $file.ReadLine()) {
$count += 1
$s = $line -replace "`n", "`r`n"
$outstream.WriteLine($s)
}
$file.close()
$outstream.close()
Write-Host ([string] $count + ' lines have been processed.')