Get-Content и отображение управляющих символов, таких как `r - визуализация управляющих символов в строках

Какой флаг мы можем передать Get-Content отображать управляющие символы, такие как \r\n или же \n?

То, что я пытаюсь сделать, это определить, имеют ли окончания строки файла стиль Unix или Dos. Я пробовал просто бегать Get-Content, который не показывает окончание строки. Я также пытался использовать Vim с set list, который просто показывает $ независимо от того, что конец строки.

Я хотел бы сделать это с PowerShell, потому что это было бы очень полезно.

3 ответа

Решение

Одним из способов является использование параметра -Encoding в Get-Content, например:

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

Если у вас есть расширения сообщества PowerShell, вы можете использовать команду 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

Ниже пользовательская функция Debug-String , который визуализирует все управляющие символы в диапазоне ASCII в строках:

  • используя собственный PowerShell ` с префиксом escape-последовательности (например, `r для CR), где доступна собственная утилита PowerShell,

  • возврат к обозначению каретки (например, управляющий символ диапазона ASCII с кодовой точкой 0x4 - КОНЕЦ ПЕРЕДАЧИ - представлен как ^D).

    • Кроме того, вы можете использовать -CaretNotation Переключатель для представления всех управляющих символов ASCII-диапазона в нотации каретки, что дает вывод, аналогичный cat -A в Linux и cat -et на macOS/BSD.
  • Предостережение: управляющие символы вне диапазона ASCII (кодовые точки диапазона ASCII) 0x0 - 0x7F) представлены без различия как (символ замены Unicode, U+FFFD).

Применительно к вашему варианту использования вы будете использовать (требуется PSv3 +, из-за использования Get-Content -Raw обеспечить чтение файла в целом; без него информация об окончаниях строки была бы потеряна):

Get-Content -Raw $file | Debug-String

Два простых примера:


Использование обозначений escape-последовательностей PowerShell. Обратите внимание, что это похоже только на no-op: последовательности с префиксом `внутри строк"..."создают фактические управляющие символы.

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

С помощью -CaretNotation с выводом, аналогичным cat -A в Linux:

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

Debug-String исходный код:

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  { '`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; since we have no good representation
            # for them, we simpy output the Unicode replacement char.
            default { '�' }
          }
      } # 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.

Any non-ASCII control characters are visualized without distinction as 
the Unicode replacement character, "�".

.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
> "a`ab`t c`0d`r`n" | Debug-String
a`ab`t c`0d`r`n

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

Вот один из способов использования замены регулярного выражения:

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
Другие вопросы по тегам