GnuWin32 / sed неожиданное поведение в Powershell
Я использую инструменты GnuWin32 в командной строке Windows /Powershell.
Что посмотреть
11:15 enlil D:\Users\x> Get-ChildItem .gitconfig | sed "s/ */ /g"
D i r e c t o r y : D : \ U s e r s \ x
M o d e L a s t W r i t e T i m e L e n g t h N a m e
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- a - - - 6 / 2 3 / 2 0 1 4 4 : 1 1 P M 5 6 . g i t c o n f i g
Что я ожидал увидеть:
11:15 enlil D:\Users\x> ls .gitconfig | sed "s/ */ /g"
Directory: D:\Users\x
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 6/23/2014 4:11 PM 56 .gitconfig
Моя цель - избавиться от лишних пробелов между столбцами данных, которые добавляются PowerShell. Самое смешное, что это прекрасно работает на одном компьютере (с Win8.1), но не работает на другом компьютере с Win7.
И это работает для простых примеров:
11:49 enlil D:\Users\x> echo "t a t" | sed "s/ */ /g"
t a t
Любая помощь будет высоко ценится.
К вашему сведению - нормальный вывод Get-ChildItems выглядит следующим образом:
11:22 enlil D:\Users\x> ls .gitconfig
Directory: D:\Users\x
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 6/23/2014 4:11 PM 56 .gitconfig
1 ответ
Это Юникод. В основе sed лежит Unicode без 2-байтового префикса, который PowerShell использует для различения Unicode и ASCII. Поэтому PowerShell считает, что это ASCII, и оставляет байты \0 (верхние байты 2-байтовых символов Unicode), которые отображаются в виде пробелов. А поскольку внутренне PowerShell работает с Unicode, он фактически расширяет каждый исходный байт до 2-байтового символа Unicode. Невозможно заставить PowerShell принять Unicode. Возможные способы обойти это:
Unicode поступает как вход в SED? Вряд ли, но я думаю, что это возможно. Проверь это.
Начните вывод SED с индикатора Unicode \uFEFF. Это, вероятно, то, что упущено в исходном коде SED:
_setmode(_fileno(stdout), _O_WTEXT); // probably present and makes it send Unicode wprintf(L"\uFEFF"); // probably missing
Вы можете добавить код внутри команды SED, что-то вроде
sed "1s/^/\xFF\xFE/;..." # won't work if SED produces Unicode but would work it SED passes Unicode through from its input sed "1s/^/\uFEFF/;..." # use if SED produces Unicode itself, hopefully SED supports \u
Запишите вывод sed в файл, а затем прочитайте с помощью Get-Content -Encoding Unicode. Обратите внимание, что переключение на файл должно быть выполнено в команде внутри cmd.exe, например:
cmd /c "sed ... >file"
Если вы просто разрешите> обрабатывать файл в PowerShell, он будет испорчен таким же образом.
Удалите символы \0 из полученного текста в PowerShell. Это не очень хорошо работает с международными символами, которые создают байты Unicode, содержащие код 0xA или 0xD - в итоге вы получите разделители строк вместо них.