Изменение кодировки вывода PowerShell по умолчанию на UTF-8

105

По умолчанию, когда вы перенаправляете вывод команды в файл или перенаправляете его во что-то другое в PowerShell, используется кодировка UTF-16, что бесполезно. Я хочу изменить его на UTF-8.

Это можно сделать в каждом конкретном случае, заменив >foo.txtсинтаксис на, | out-file foo.txt -encoding utf8но неудобно повторять каждый раз.

Постоянный способ настроить вещи в PowerShell - это вставить их \Users\me\Documents\WindowsPowerShell\profile.ps1; Я убедился, что этот файл действительно запускается при запуске.

Было сказано, что кодировка вывода может быть установлена, $PSDefaultParameterValues = @{'Out-File:Encoding' = 'utf8'}но я пробовал это, и это не повлияло.

https://blogs.msdn.microsoft.com/powershell/2006/12/11/outputencoding-to-the-rescue/, в котором говорится о $OutputEncodingвзглядах на первый взгляд так, как будто это должно быть актуально, но затем говорится о кодировании вывода в ASCII, чего на самом деле не происходит.

Как настроить PowerShell на использование UTF-8?

Rwallace
источник

Ответы:

162

Примечание . Следующее относится к Windows PowerShell .
См. Следующий раздел для кросс-платформенной версии PowerShell Core (v6 +) .

  • В PSv5.1 или выше , где >и >>являются фактически псевдонимами Out-File, вы можете установить кодировку по умолчанию для >/ >>/ с Out-Fileпомощью $PSDefaultParameterValuesпеременной предпочтений :

    • $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
  • В PSv5.0 или ниже вы не можете изменить кодировку для >/>> , но в PSv3 или выше описанный выше метод действительно работает для явных вызововOut-File .
    ( $PSDefaultParameterValuesПеременная предпочтений была введена в PSv3.0).

  • На PSv3.0 или выше , если вы хотите установить по умолчанию кодировку для всех командлетов , которые поддерживают
    в -Encodingпараметр
    (который в PSv5.1 + включает в себя >и >>), используйте:

    • $PSDefaultParameterValues['*:Encoding'] = 'utf8'

Если вы поместите эту команду в свои$PROFILE командлеты, такие как Out-FileиSet-Content , по умолчанию будут использовать кодировку UTF-8, но обратите внимание, что это делает ее глобальным параметром сеанса , который повлияет на все команды / сценарии, которые явно не указывают кодировку.

Точно так же не забудьте включить такие команды в свои сценарии или модули, которые вы хотите вести таким же образом , чтобы они действительно вели себя одинаково, даже когда их запускает другой пользователь или другая машина.

Предостережение : ** PowerShell, начиная с версии 5.1 , неизменно создает файлы UTF-8 _с (псевдо) спецификацией _ ** , что является обычным явлением только в мире Windows - утилиты на основе Unix не распознают эту спецификацию (см. Внизу); см. этот пост для обходных путей, которые создают файлы UTF-8 без спецификации.

Для резюме дико непоследовательного поведения кодирования символов по умолчанию во многих стандартных командлетов Windows PowerShell см нижнюю секцию.


Автоматическая $OutputEncodingпеременная не связана и применяется только к тому, как PowerShell взаимодействует с внешними программами (какую кодировку использует PowerShell при отправке им строк) - она ​​не имеет ничего общего с кодировкой, которую операторы перенаправления вывода и командлеты PowerShell используют для сохранения в файлы.


Дополнительное чтение: кроссплатформенная перспектива: PowerShell Core :

PowerShell теперь является кроссплатформенным , благодаря своей редакции PowerShell Core , чья кодировка - разумно - по умолчанию использует UTF-8 без спецификации , что соответствует Unix-подобным платформам.

  • Это означает , что исходный код-файлы без спецификации предполагается UTF-8, и с помощью >/ Out-File/ по Set-Contentумолчанию в спецификацию менее UTF-8; явное использование utf8 -Encodingаргумента также создает UTF-8 без спецификации , но вы можете выбрать создание файлов с псевдо-спецификацией со utf8bomзначением.

  • Если вы создаете сценарии PowerShell с помощью редактора на Unix-подобной платформе, а в настоящее время даже в Windows с кросс-платформенными редакторами, такими как Visual Studio Code и Sublime Text, полученный *.ps1файл обычно не будет иметь псевдо-спецификации UTF-8:

    • Это отлично работает в PowerShell Core .
    • Он может сломаться в Windows PowerShell , если файл содержит символы, отличные от ASCII; если вам действительно нужно использовать символы, отличные от ASCII, в ваших скриптах, сохраните их как UTF-8 с BOM .
      Без спецификации Windows PowerShell (неверно) интерпретирует ваш сценарий как закодированный в устаревшей кодовой странице «ANSI» (определяемой языковым стандартом системы для приложений, предшествующих Unicode; например, Windows-1252 в системах на английском языке).
  • С другой стороны , файлы , которые делают имеют UTF-8 псевдо-BOM может быть проблематичным , на Unix-подобных платформах, так как они вызывают Unix утилит , таких как cat, sedи awk- и даже некоторые редакторы , такие как gedit- чтобы передать псевдо-BOM через , т.е. рассматривать это как данные .

    • Это не всегда может быть проблемой, но определенно может быть, например, когда вы пытаетесь прочитать файл в строке bash, скажем, text=$(cat file)или text=$(<file)- результирующая переменная будет содержать псевдо-спецификацию в качестве первых 3 байтов.

Несогласованное поведение кодировки по умолчанию в Windows PowerShell :

К сожалению, кодировка символов по умолчанию, используемая в Windows PowerShell, очень непоследовательна; Кросс-платформенная версия PowerShell Core , как обсуждалось в предыдущем разделе, похвально положила этому конец.

Заметка:

  • Нижеследующее не претендует на охват всех стандартных командлетов.

  • Поиск в Google имен командлетов для поиска их тем справки теперь по умолчанию показывает версию тем PowerShell Core ; используйте раскрывающийся список версий над списком тем слева, чтобы переключиться на версию Windows PowerShell .

  • На момент написания этой статьи в документации часто неверно утверждается, что ASCII является кодировкой по умолчанию в Windows PowerShell - см. Эту проблему с документацией GitHub .


Командлеты, которые пишут :

Out-Fileи >/ >>создать "Unicode" - UTF-16LE - файлы по умолчанию - в которых каждый символ диапазона ASCII (тоже) представлен двумя байтами, что заметно отличается от Set-Content/ Add-Content(см. следующий пункт); New-ModuleManifestа Export-CliXmlтакже создавать файлы UTF-16LE.

Set-ContentAdd-Contentесли файл еще не существует / пуст) использует кодировку ANSI (кодировку, заданную устаревшей кодовой страницей ANSI активного языкового стандарта, которую вызывает PowerShell Default).

Export-Csvдействительно создает файлы ASCII, как -Appendописано в документации, но см. примечания ниже.

Export-PSSession по умолчанию создает файлы UTF-8 с спецификацией.

New-Item -Type File -Value в настоящее время создает UTF-8 без спецификации (!).

В Send-MailMessageразделе справки также утверждается, что по умолчанию используется кодировка ASCII - я лично не проверял это утверждение.

Start-Transcript неизменно создает файлы UTF-8 с BOM, но см. примечания -Appendниже.

Re команды, которые добавляются в существующий файл:

>>/ Out-File -AppendНе делать не попытки соответствовать кодировке файла существующего контента . То есть они вслепую применяют свою кодировку по умолчанию, если не указано иное -Encoding, что невозможно >>(за исключением косвенного в PSv5.1 +, через $PSDefaultParameterValues, как показано выше). Вкратце: вы должны знать кодировку содержимого существующего файла и добавлять его, используя ту же кодировку.

Add-Contentявляется похвальным исключением: при отсутствии явного -Encodingаргумента он обнаруживает существующую кодировку и автоматически применяет ее к новому контенту. Спасибо, js2010 . Обратите внимание, что в Windows PowerShell это означает, что применяется кодировка ANSI, если существующее содержимое не имеет спецификации, тогда как в PowerShell Core используется кодировка UTF-8.

Это несоответствие между Out-File -Append/ >>и Add-Content, которое также влияет на PowerShell Core , обсуждается в этом выпуске GitHub .

Export-Csv -Append частично соответствует существующей кодировке: он слепо добавляет UTF-8, если кодировка существующего файла является любой из ASCII / UTF-8 / ANSI, но правильно соответствует UTF-16LE и UTF-16BE.
Другими словами: при отсутствии спецификации Export-Csv -Appendпредполагается , что используется UTF-8, тогда как Add-Contentпредполагается, что ANSI.

Start-Transcript -Append частично соответствует существующей кодировке: она правильно соответствует кодировкам с BOM , но по умолчанию используется кодировка ASCII с потенциально потерями при ее отсутствии.


Командлеты, которые читают (то есть кодировку, используемую при отсутствии спецификации ):

Get-Contentи по Import-PowerShellDataFileумолчанию используется ANSI ( Default), что согласуется с Set-Content.
ANSI - это также то, что по умолчанию использует сам движок PowerShell при чтении исходного кода из файлов.

В отличие от этого Import-Csv, Import-CliXmlи Select-Stringпредположим , UTF-8 в отсутствие спецификации.

mklement0
источник
Не могли бы вы объяснить, как >/ >>стали эффективными псевдонимами для Out-File5.1?
Максимилиан Бёрсли
@ TheIncorrigible1: Возможно, PetSerAl указал мне на это, но я не помню, где и как. Windows PowerShell имеет закрытый исходный код, но поскольку такая же связь квази-псевдонима применяется и к PowerShell Core, вы сможете найти ее в исходном коде последней.
mklement0
2
Я не возражаю, @EliaWeiss, но это конкретно Windows PowerShell, и в конечном итоге они сделали это правильно в PowerShell Core .
mklement0
2
@Marc: VS Code и другие современные кроссплатформенные редакторы похвально по умолчанию используют UTF-8, что, однако, означает, что они неправильно интерпретируют файлы в кодировке ANSI. Блокнот использует эвристику, чтобы угадать кодировку. Дело в том, что это только предположение , потому что любой файл в кодировке UTF-8 также является технически допустимым файлом в кодировке ANSI (но не наоборот). Было бы замечательно, если бы все в Windows по умолчанию использовало UTF-8 в отсутствие спецификации, как это делают Unix-подобные платформы, но это не так, особенно в Windows PowerShell, хотя, к счастью, теперь это так и в PowerShell Core.
mklement0
2
Чтобы посмотреть текущее значение , если некоторые, просто введите$PSDefaultParameterValues
Сэндберг
3

Чтобы быть кратким, используйте:

write-output "your text" | out-file -append -encoding utf8 "filename"
pbies
источник