7

我们可以传递什么标志Get-Content来显示控制字符,例如\r\nor \n

我想要做的是确定文件的行尾是 Unix 还是 Dos 风格。我试过简单地运行Get-Content,它没有显示任何行尾。我也尝试过将 Vim 与 一起使用,无论行尾是什么set list,它都只会显示。$

我想用 PowerShell 来做这件事,因为那会非常有用。

4

3 回答 3

8

一种方法是使用 Get-Content 的 -Encoding 参数,例如:

Get-Content foo.txt -Encoding byte | % {"0x{0:X2}" -f $_}

如果你有PowerShell Community Extensions,你可以使用 Format-Hex 命令:

Format-Hex foo.txt

Address:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F ASCII
-------- ----------------------------------------------- ----------------
00000000 61 73 66 09 61 73 64 66 61 73 64 66 09 61 73 64 asf.asdfasdf.asd
00000010 66 61 73 0D 0A 61 73 64 66 0D 0A 61 73 09 61 73 fas..asdf..as.as

如果您真的想在输出中看到“\r\n”而不是按照 BaconBits 的建议进行操作,但您必须使用 -Raw 参数,例如:

(Get-Content foo.txt -Raw) -replace '\r','\r' -replace '\n','\n' -replace '\t','\t'

输出:

asf\tasdfasdf\tasdfas\r\nasdf\r\nas\tasd\r\nasdfasd\tasf\tasdf\t\r\nasdf
于 2014-12-01T18:47:42.377 回答
7

下面是自定义函数Debug-String,它将字符串中的控制字符可视化

  • 在可用的情况下,使用 PowerShell 自己的`-prefixed 转义序列表示法(例如,`r对于 CR),其中可以使用本机 PowerShell 转义,

  • 回退到插入符号(例如,带有代码点的 ASCII 范围控制字符0x4- END OF TRANSMISSION - 表示为^D)。

    • 或者,您可以使用该-CaretNotation开关以插入符号表示所有ASCII 范围控制字符,这为您提供类似于cat -ALinux 和cat -etmacOS/BSD 上的输出。
  • 所有其他控制字符,即ASCII 范围之外的那些(跨越代码点的 ASCII 范围0x0- 0x7F)以 形式表示`u{<hex>},其中<hex>是十六进制。最多 6 位的代码点表示;例如,`u{85}是 Unicode 字符。U+0085, NEXT LINE 控制字符;现在,可扩展字符串 ( "...") 也支持此表示法,但仅在 PowerShell Core中。

应用于您的用例,您将使用(需要PSv3+,因为使用Get-Content -Raw以确保文件被作为一个整体读取;没有它,有关行尾的信息将丢失):

Get-Content -Raw $file | Debug-String

两个简单的例子:


使用 PowerShell 的转义序列符号。请注意,这看起来只是一个无操作:“...”字符串中的 `-prefixed 序列创建实际的控制字符。

PS> "a`ab`t c`0d`r`n" | Debug-String
a`ab`t c`0d`r`n

使用-CaretNotation, 输出类似于cat -ALinux:

PS> "a`ab`t c`0d`r`n" | Debug-String -CaretNotation
a^Gb^I c^@d^M$

Debug-String源代码:

注意:下面的函数也可作为MIT 许可的 Gist使用,具有附加功能,特别是将空格显示为·和将非 ASCII 字符显示为转义序列( -UnicodeEscapes) 的选项,以及将字符串打印为 PowerShell 字符串文字的选项( -AsSourceCode)。只有 Gist 将继续保持下去。

假设您已经查看了链接代码以确保它是安全的(我可以亲自向您保证,但您应该始终检查),您可以直接安装它,如下所示

irm https://gist.github.com/mklement0/7f2f1e13ac9c2afaf0a0906d08b392d1/raw/Debug-String.ps1 | iex
Function Debug-String {
  param(
    [Parameter(ValueFromPipeline, Mandatory)]
    [string] $String
    ,
    [switch] $CaretNotation
  )

  begin {
    # \p{C} matches any Unicode control character, both inside and outside
    # the ASCII range; note that tabs (`t) are control character too, but not spaces.
    $re = [regex] '\p{C}'
  }

  process {

    $re.Replace($String, {
      param($match)
      $handled = $False
      if (-not $CaretNotation) {
        # Translate control chars. that have native PS escape sequences into them.
        $handled = $True
        switch ([Int16] [char] $match.Value) {
          0  { '`0'; break }
          7  { '`a'; break }
          8  { '`b'; break }
          12 { '`f'; break }
          10 { '`n'; break }
          13 { '`r'; break }
          9  { '`t'; break }
          11 { '`v'; break }
          default { $handled = $false }
        } # switch
      }
      if (-not $handled) {
          switch ([Int16] [char] $match.Value) {
            10 { '$'; break } # cat -A / cat -e visualizes LFs as '$'
            # If it's a control character in the ASCII range, 
            # use caret notation too (C0 range).
            # See https://en.wikipedia.org/wiki/Caret_notation
            { $_ -ge 0 -and $_ -le 31 -or $_ -eq 127 } {
              # Caret notation is based on the letter obtained by adding the
              # control-character code point to the code point of '@' (64).
              '^' + [char] (64 + $_)
              break
            }
            # NON-ASCII control characters; use the - PS Core-only - Unicode
            # escape-sequence notation:
            default { '`u{{{0}}}' -f ([int16] [char] $_).ToString('x') }
          }
      } # if (-not $handled)
    })  # .Replace
  } # process

}

为简洁起见,我没有在上面包含基于评论的帮助;这里是:

<#
.SYNOPSIS
Outputs a string in diagnostic form.

.DESCRIPTION
Prints a string with normally hidden control characters visualized.

Common control characters are visualized using PowerShell's own escaping 
notation by default, such as
"`t" for a tab, "`n" for a LF, and "`r" for a CR.

Any other control characters in the ASCII range (C0 control characters)
are represented in caret notation (see https://en.wikipedia.org/wiki/Caret_notation).

If you want all ASCII range control characters visualized using caret notation,
except LF visualized as "$", similiar to `cat -A` on Linux, for instance, 
use -CaretNotation.

Non-ASCII control characters are visualized by their Unicode code point
in the form `u{<hex>}, where <hex> is the hex. representation of the
code point with up to 6 digits; e.g., `u{85} is U+0085, the NEXT LINE
control char.

.PARAMETER CaretNotation
Causes LF to be visualized as "$" and all other ASCII-range control characters
in caret notation, similar to `cat -A` on Linux.

.EXAMPLE
PS> "a`ab`t c`0d`r`n" | Debug-String
a`ab`t c`0d`r`n

.EXAMPLE
PS> "a`ab`t c`0d`r`n" | Debug-String -CaretNotation
a^Gb^I c^@d^M$
#>
于 2017-07-27T16:58:30.763 回答
2

这是使用正则表达式替换的一种方法:

function Printable([string] $s) {
    $Matcher = 
    {  
      param($m) 

      $x = $m.Groups[0].Value
      $c = [int]($x.ToCharArray())[0]
      switch ($c)
      {
          9 { '\t' }
          13 { '\r' }
          10 { '\n' }
          92 { '\\' }
          Default { "\$c" }
      }
    }
    return ([regex]'[^ -~\\]').Replace($s, $Matcher)
}

PS C:\> $a = [char[]](65,66,67, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)

PS C:\> $b = $a -join ""

PS C:\> Printable $b
ABC\1\2\3\4\5\6\7\8\t\n\11\12\r
于 2014-12-01T18:58:31.420 回答