Powershell扭曲ASCII文本

4

当我尝试修改 hosts 文件时,会出现额外的字符和行。例如,这个选择字符串没有取出任何内容,但是这两个文件是不同的:

get-content -Encoding ascii C:\Windows\system32\drivers\etc\hosts |
  select-string -Encoding ascii -notmatch "thereisnolinelikethis" |
  out-file -Encoding ascii c:\temp\testfile

PS C:\temp> (get-filehash C:\windows\system32\drivers\etc\hosts).hash
C54C246D2941F02083B85CE2774D271BD574F905BABE030CC1BB41A479A9420E

PS C:\temp> (Get-FileHash C:\temp\testfile).hash
AC6A1134C0892AD3C5530E58759A09C73D8E0E818EC867C9203B9B54E4B83566

这可能是因为Get-Content返回一个数组,将文件分解成数组并将其作为字符串写回时,可能会引入额外的换行符。 - briantist
是 Select-String 添加了额外的行...真的很好奇为什么。 - Cole9350
3个回答

2

我认为这更多是PowerShell的F&O(格式化和输出)引擎的问题。请记住,Select-String输出一个名为MatchInfo的丰富对象。当该对象到达输出末尾时,它需要呈现为字符串。我认为正是这种呈现/格式化注入了额外的行。MatchInfo上的属性之一是匹配的行(或未匹配的行)。如果只传递管道下的Line属性,似乎可以更好地工作(散列匹配):

Get-Content C:\Windows\system32\drivers\etc\hosts |
    Select-String -notmatch "thereisnolinelikethis" |
    Foreach {$_.Line} |
    Out-File -Encoding ascii c:\temp\testfile

顺便说一下,只有在输出回文件时才需要指定ASCII编码。在PowerShell的其他任何地方,都可以让字符串以Unicode流动。

话虽如此,在这种情况下,我会使用 Where-Object 而不是 Select-String 。Where-Object 是一个过滤命令,也就是你想要的。而 Select-String 则将输入从一种形式(字符串)转换为另一种对象(MatchInfo)。


2
我可以确认您的命令在输出文件的开头和结尾会不可避免地导致额外的换行。Powershell还将原始文件中的制表符转换为四个空格。虽然我无法解释原因,但这些命令可以避免这些问题:请尝试使用以下代码:
Get-Content -Path C:\Windows\System32\drivers\etc\hosts -Encoding Ascii | 
  Where-Object { -not $_.Contains("thereisnolinelikethis")  } |
  Out-File -FilePath "c:\temp\testfile" -Encoding Ascii

0

Out-File 会在 testfile 文件末尾添加一个换行符 ("`r`n")。

C:\Windows\System32\drivers\etc\hosts 默认情况下不包含末尾的换行符,这就是为什么你得到了不同的文件哈希值。


如果您使用StreamReader打开文件,您会发现底层流的长度不同(由于新文件中的尾随换行符)。
PS C:\> $Hosts = [System.IO.StreamReader]"C:\Windows\System32\drivers\etc\hosts"
PS C:\> $Tests = [System.IO.StreamReader]"C:\temp\testfile"
PS C:\> $Hosts.BaseStream.Length
822
PS C:\> $Tests.BaseStream.Length
824
PS C:\> $Tests.BaseStream.Position = 822; $Tests.Read(); $Tests.Read()
13
10

ASCII字符13(0x0D)和10(0x0A)对应于[System.Environment] :: NewLineCR + LF


好的,但是为什么?还有这个前导换行符从哪里来的? - Cole9350
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Mathias R. Jessen
你错了,你没有注意到它是如何在文件顶部添加一个新行的。这是一个尾随换行符和一个前导换行符,在select-string中发生而不是out-file。 - Cole9350
@Cole9350 Out-File 没有将其添加到文件顶部。Select-String 正是这样做的,这就是为什么我建议在我的答案中不要使用它。 - Ashigore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接