Случайные разрывы строк в стандартном выводе ошибок PowerShell - PullRequest
0 голосов
/ 21 сентября 2018

Я хочу конвертировать многие файлы .iso в .mp4 с помощью HandBrake, поэтому я пытаюсь использовать интерфейс командной строки.Я предпочел бы написать свои сценарии для этого в powershell вместо командных файлов.Однако стандартная ошибка содержит разрывы строк в случайном месте, если я использую powershell.

Для устранения неполадок я создал упрощенный сценарий как в powershell, так и в пакетном режиме.

Powershell:

& "$Env:ProgramFiles\HandBrake\HandBrakeCLI.exe" @(
    '--input', 'V:\',
    '--title', '1', '--chapter', '1',
    '--start-at', 'duration:110', '--stop-at', 'duration:15',
    '--output', 'pmovie.mp4',
    '--format', 'av_mp4'
    ) > ".\pstd.txt" 2> ".\perr.txt"

Пакетный файл:

"%ProgramFiles%\HandBrake\HandBrakeCLI.exe" --input V:\ --title 1 --chapter 1 --start-at duration:110 --stop-at duration:15 --output ".\cmovie.mp4" --format av_mp4 > ".\cstd.txt" 2> ".\cerr.txt"

Оба сценария создают один и тот же файл .mp4, отличие состоит только в стандартном выводе ошибок, который они создают:

Powershell:

HandBrakeCLI.exe : [10:41:44] hb_init: starting libhb thread
At C:\Test\phandbrake.ps1:1 char:2
+ & <<<<  "$Env:ProgramFiles\HandBrake\HandBrakeCLI.exe" @(
    + CategoryInfo          : NotSpecified: ([10:41:44] hb_i...ng libhb thread 
   :String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

[10:41:44] thread 541fc20 started ("libhb")
HandBrake 1.1.2 (2018090500) - MinGW x86_64 - https://handbrake.fr
8 CPUs detected

O
pening V:\...

[10:41:44] CPU: Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz

[10:41:44]  - Intel microarchitecture Sandy Bridge
[10:41:44]  - logical processor count: 8

[10:41:44] Intel Quick Sync Video support: no

[10:41:44] hb_scan: path=V:\, title_index=1

src/libbluray/disc/disc.c:424: error opening file BDMV\index.bdmv

src/libbluray/disc/disc.c:424: error opening file BDMV\BACKUP\index.bdmv

[10:41:44] bd: not a bd - trying as a stream/file instead

libdvdnav: Using dvdnav version 6.0.0

l
ibdvdnav: Unable to open device file V:\.
libdvdnav: vm: dvd_read_name failed
libdvdnav: DVD disk re
ports i
tself wi
th Region mask 0x
0000000
0. Reg
ions:
 1 2 3 4 5 
6 7 8

Пакетный файл:

[10:41:35] hb_init: starting libhb thread
[10:41:35] thread 5a2cc30 started ("libhb")
HandBrake 1.1.2 (2018090500) - MinGW x86_64 - https://handbrake.fr
8 CPUs detected
Opening V:\...
[10:41:35] CPU: Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz
[10:41:35]  - Intel microarchitecture Sandy Bridge
[10:41:35]  - logical processor count: 8
[10:41:35] Intel Quick Sync Video support: no
[10:41:35] hb_scan: path=V:\, title_index=1
src/libbluray/disc/disc.c:424: error opening file BDMV\index.bdmv
src/libbluray/disc/disc.c:424: error opening file BDMV\BACKUP\index.bdmv
[10:41:35] bd: not a bd - trying as a stream/file instead
libdvdnav: Using dvdnav version 6.0.0
libdvdnav: Unable to open device file V:\.
libdvdnav: vm: dvd_read_name failed
libdvdnav: DVD disk reports itself with Region mask 0x00000000. Regions: 1 2 3 4 5 6 7 8

libdvdread: Attempting to retrieve all CSS keys
libdvdread: This can take a _long_ time, please be patient

libdvdread: Get key for /VIDEO_TS/VIDEO_TS.VOB at 0x00000130
libdvdread: Elapsed time 0

Это беспокоит меня, потому что я хотел бы проверить эти текстовые файлы, чтобы убедиться, что не было ошибок во время

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

Вопрос: что я могусделать, чтобы получить стандартный вывод ошибок из PowerShell без этих случайных разрывов строк?

Ответы [ 3 ]

0 голосов
/ 08 октября 2018

Я думаю, что проблема в том, что консоль имеет определенную ширину, а сама консоль по существу перенаправляется в файл.

Мое решение - перенаправить вывод непосредственно в конвейер., используя:

2>&1 #Interpreted by the console
2>&1 | x #Output directly to x

И затем используя Out-File с доступным параметром -Width:

$(throw thisisnotsometthingyoucanthrowbutisinfactaverylongmessagethatdemonstratesmypoint) 2>&1 |
 Out-File "test.txt" -Width 10000

В этом случае powershell напишет 10 000 символов перед переносом текста.

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

Например, вы можете использовать эту функцию , которая печатаетточные управляющие символы, которые вызывают разрывы строк.

$(throw error) 2>&1 | Out-String | Debug-String

Затем вы можете просмотреть выходные данные и заменить проблемные символы, например:

$(throw error) 2>&1 | Out-String | % {$_ -replace "`r"} | Out-File "test.txt" -Width 10000
0 голосов
/ 14 октября 2018

Полезный ответ Бёрта Харриса показывает вам один способ избежать проблемы, через Start-Process, который требует, чтобы вы структурировали команду принципиально иначе, однако.

Если вывод, которыйдостаточно создать эквивалентный пакетный файл, есть более простой способ: просто вызовите cmd /c и позвольте cmd обработать перенаправления вывода , как в вашем пакетном файле:

cmd /c "`"`"$Env:ProgramFiles\HandBrake\HandBrakeCLI.exe`"`"" @(
    '--input', 'V:\',
    '--title', '1', '--chapter', '1',
    '--start-at', 'duration:110', '--stop-at', 'duration:15',
    '--output', 'pmovie.mp4',
    '--format', 'av_mp4'
    ) '> .\pstd.txt 2> .\perr.txt'

Примечаниекак два выходных перенаправления передаются как одна строка в кавычках , чтобы гарантировать, что они интерпретируются cmd.exe, а не PowerShell.

Также обратите внимание навстроенные экранированные двойные кавычки (`") вокруг исполняемого пути, чтобы гарантировать, что cmd.exe видит весь путь как одну строку в двойных кавычках.


Что касается дополнительных разрывов строк, которые вывидя: у меня нет конкретных объяснений, но я могу рассказать вам , как > и 2> работают по-разному в PowerShell - оба по сравнению с cmd.exe (пакетные файлы) и Start-Process с -RedirectStandard*:

  • cmd.exe (>) записывает необработанные байты в указанный целевой файл, как при перенаправлении stdout (просто > или, явно, 1>), так и stderr (2>));как таковой, вывод текста внешними программами, такими как HandBrakeCLI.exe, передается как есть.

  • Start-Process, который использует .NET API под капотом, делает по существу то же самоекогда заданы параметры -RedirectStandardOutput и / или -RedirectStandardError.

В отличие от этого, собственный оператор Powershell > работает по-разному:

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

  • Вывод из внешних программ isпредполагается, что text , кодировка которого по умолчанию считается кодировкой OEM-символов системы, что отражено в [console]::OutputEncoding и chcp.Декодированный текст загружается в строки .NET (которые по сути основаны на UTF-16) построчно .

    • Для redirected stdout output , эти строки перекодируются при выводе в целевой файл , по умолчанию используется следующая кодировка:

      • Windows PowerShell: UTF-16LE («Unicode»)
      • PowerShell Core: UTF-8 без спецификации
      • Примечание. Только в Windows PowerShell v5.1 или выше, и PowerShell Core может изменить эти значения по умолчанию - подробности см. в этом ответе .
    • В отличие от при перенаправлении stderr output , через поток 2 (поток ошибок PowerShell), строки заключаются в объекты ошибок (экземпляры типа [System.Management.Automation.ErrorRecord]) перед выводом, и результирующие объектыконвертируется в строки на основе системы форматирования вывода PowerShell, и к outp применяется та же кодировка символов, что и вышедо целевого файла.

      • Вы можете увидеть подтверждение этого в выходных данных, содержащих дополнительную информацию и строки, такие как HandBrakeCLI.exe : [10:41:44] hb_init: starting libhb thread и At C:\Test\phandbrake.ps1:1 char:2, ...
      • Это такжеозначает, что могут быть введены дополнительные разрывы строк, потому что текст, создаваемый системой форматирования вывода, предполагает фиксированную ширину строки, основанную на ширине окна консоли.
      • Тем не менее, это не объясняет странно размещенные разрывы строк вваш случай.
0 голосов
/ 08 октября 2018

Вы можете попробовать команду Start-Process с параметрами -RedirectStandardError,
-RedirectStandardInput и -Wait.

Эти параметры -Redirect... в Start-Process делают уровень ОС I /O перенаправление непосредственно в целевой файл, как это делает большинство оболочек.Насколько я понимаю, переадресация угловых скобок PowerShell работает не так, вместо этого они направляют выходные данные через другой конвейер PowerShell, используя Write-File (или что-то еще), который вставляет разрывы строк между полученными строками.

Я не уверен в точных деталях этого, но я рад слышать, что это, похоже, решает проблему для вас так же, как и для меня.

...