使用 Powershell 从文件中删除最后一行
Posted
技术标签:
【中文标题】使用 Powershell 从文件中删除最后一行【英文标题】:Remove last line from file with Powershell 【发布时间】:2012-07-23 11:45:27 【问题描述】:我正在使用
gc FileWithEmptyLines.txt | where $_ -ne "" > FileWithNoEmptyLines.txt
删除 s-s-rS 放在我的 CSV 底部的空行。
但是,包含数据的最后一行以 CRLF 结尾(如在 Notepad++ 中查看的那样) - 这并没有被删除,因此从技术上讲,文件底部仍然有一个空白行。
有没有办法从最后一行删除这个 CRLF(当然,保持数据完整)?
【问题讨论】:
这不是“技术上的”。除非文件以 CR LF CR LF 结尾,否则末尾没有空行。从技术上讲。 Ignacio,这取决于你将它理解为 separator 行还是 terminator 行;) 【参考方案1】:我不确定这对这种情况有多适用,但我在谷歌上搜索删除文本文件的最后一行导致我来到这里,上面的示例/解决方案不起作用。这是我可以用来让它工作的命令:
$file = "file.txt"
Get-Content $file | Measure-Object -Line
$a = (Get-Content $file | Measure-Object)
(Get-Content $file) | ? ($a.count-1)-notcontains $_.ReadCount | Set-Content $file
如果您正在处理一个大文件,您可能需要先将其通过管道传输到一个临时文件。
【讨论】:
这似乎会删除倒数第二行。将 ($a.count-1) 更改为 ($a.count-0) 允许它“删除”最后一行。将该数字调整为所需的计数,以从下往上删除特定的行号。请记住,在这种情况下,第一行(底部)是 0。【参考方案2】:对于“UCS-2 Little Endian”文件格式,使用这个:
$stream = [IO.File]::Open($filename, [IO.FileMode]::Open)
$stream.Position = $stream.Length - 4
$bytes = 0..3 | % $stream.ReadByte()
$compareBytes = 13,0,10,0 # CR,LF
echo "bytes: "$bytes
if ("$bytes" -eq "$compareBytes")
$stream.SetLength($stream.Length - 4)
$stream.Close()
$stream.Dispose()
【讨论】:
【参考方案3】:当您使用Get-Content
读取文件时,它会将每一行作为字符串沿管道传输。当Out-File
(本质上是>
的别名)获取这些字符串时,它总是附加一个行终止符序列。如果文件不是太大,请尝试以下操作:
$text = [IO.File]::ReadAllText("c:\FileWithEmptyLinesAtEnd.txt")
[IO.File]::WriteAllText("c:\FileWithEmptyLinesAtEnd.txt", $text.TrimEnd())
这是之前的文件:
14> fhex .\FileWithEmptyLinesAtEnd.txt
Address: 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII
-------- ----------------------------------------------- ----------------
00000000 73 65 72 76 65 72 31 2C 73 65 72 76 65 72 32 2E server1,server2.
00000010 64 6F 6D 61 69 6E 2E 6C 6F 63 61 6C 2C 73 65 72 domain.local,ser
00000020 76 65 72 33 0D 0A 20 20 20 20 20 20 ver3..
之后:
19> fhex .\FileWithEmptyLinesAtEnd.txt
Address: 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII
-------- ----------------------------------------------- ----------------
00000000 73 65 72 76 65 72 31 2C 73 65 72 76 65 72 32 2E server1,server2.
00000010 64 6F 6D 61 69 6E 2E 6C 6F 63 61 6C 2C 73 65 72 domain.local,ser
00000020 76 65 72 33 ver3
【讨论】:
这似乎没有任何作用..?文件没有被触及。【参考方案4】:如果您已经知道文件的最后一件事是要删除的 CRLF(并且您也知道编码),那么您可以走捷径:
$stream = [IO.File]::OpenWrite('foo.txt')
$stream.SetLength($stream.Length - 2)
$stream.Close()
$stream.Dispose()
这是文件的就地截断。它无需将所有文件读入内存即可工作(如果您有一个 very 大文件,那就太好了)。它适用于 ASCII、Latin-* 和 UTF-8。它不适用于 UTF-16(在这种情况下,您必须从末尾删除四个字节)。
您可以额外检查最后两个字节是否确实您要删除:
$stream = [IO.File]::Open('foo.txt', [IO.FileMode]::Open)
$stream.Position = $stream.Length - 2
$bytes = 0..1 | % $stream.ReadByte()
$compareBytes = 13,10 # CR,LF
if ("$bytes" -eq "$compareBytes")
$stream.SetLength($stream.Length - 2)
$stream.Close()
$stream.Dispose()
再次,如果您使用其他编码,请进行调整,例如对于 UTF-16,您需要与 0,10,0,13
或 10,0,13,0
进行比较。
同意,这不是很 PowerShell-ey,但自从我不得不处理 700-MiB 的数据库转储后,我对将潜在的大文件完全读入内存持谨慎态度;)
【讨论】:
这看起来是一个很好的解决方案,但我收到此错误:使用“1”参数调用“SetLength”的异常:“需要非负数。参数名称:值”行: 2 char:18 + $stream.SetLength 嗯,听起来您是在一个空文件上执行此操作(在第一个示例中,它可能是事先不存在的文件)。 这里无法真正重现。该代码对我有用,并正确删除了最后两个字节,在后一个示例中,仅当它们确实是 CRLF 时。 我得到了它的工作......第一行中的文件名必须是完全限定的(“C:\File.txt”)。谢谢! 就我而言,这只是删除了几个字符,并没有真正删除整个最后一行。【参考方案5】:试试这个,虽然它会从你的文件中删除所有空行
(Get-Content c:\FileWithEmptyLinesAtEnd.txt) |
Where-Object $_ -match '\S' |
Out-File c:\FileWithEmptyLinesAtEnd.txt
【讨论】:
我很确定它仍然会在文件的最后一行放置一个结束 CRLF。以上是关于使用 Powershell 从文件中删除最后一行的主要内容,如果未能解决你的问题,请参考以下文章