Трубный вывод командной строки построчно в Windows

253
Kidburla

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

powershell "startmyserver | tee server.log"

Проблема заключается в том, что канал вызывает выполнение первой команды и ее полное выполнение до выполнения второй команды. Это означает, что я не могу контролировать стандартный вывод моего сервера, пока он действительно работает, что я и пытаюсь сделать (я не хочу выключать сервер, чтобы просто проверить самые последние сообщения журнала).

Для более простого примера я попробовал pause. Ну, pauseв Powershell не существует, поэтому мне пришлось запустить его во вложенной cmdоболочке:

powershell "cmd /c pause | tee test.txt"

Неудивительно, что после выполнения этой команды я просто получаю мигающий курсор. Через некоторое время я нажимаю клавишу, а затем появляется «Нажать любую клавишу для продолжения» и записывается в файл практически одновременно.

То, что я хочу сделать, это канал для потоковой передачи stdout строка за строкой для следующей команды. Другими словами, всякий раз, когда он встречает символ EOL, он должен посылать некоторый вывод, и это должно (в моем случае tee) приводить к тому, что текст появляется на экране и одновременно записывается в файл. (На самом деле, я даже не беспокоюсь о том, записывается ли текст в файл построчно, он может быть записан полностью в конце, хотя это не было бы идеально. Я просто хочу иметь возможность видеть строки на экране как они написаны.)

Возможно ли это в командной строке и / или Powershell?

2
@PimpJuiceIT Я думаю, что это имеет значение с двойными кавычками. Если вы запустите `powershell cmd / c pause | tee "test.txt" `вы используете tee в текущем контексте. Я запускаю это из cmd (не ps1), поэтому эта команда не будет выполнена, поскольку `tee` - это команда Powershell. если эта команда сработала для вас, я предполагаю, что (а) у вас есть еще одна «тройник» в вашей системе или (б) вы запустили ее из Powershell. Ни один из которых не является моим вариантом использования. Kidburla 5 лет назад 0
@PimpJuiceIT у вас есть другой пример команды, которую я мог бы использовать вместо `pause`? Я использовал `pause` просто для удобства, потому что не хотел, чтобы команда сразу заканчивалась и поэтому не позволяла определить, были ли строки переданы до завершения команды Kidburla 5 лет назад 0
Может быть, спать, возможно, но это кажется, что Вы нашли рабочее решение, так что это все спорно в настоящее время. Pimp Juice IT 5 лет назад 0

1 ответ на вопрос

1
harrymc

Эта проблема в переполнении стека объясняется тем фактом, что PowerShell Tee-Objectне сбрасывает поток вывода, а только ждет, пока источник сделает это, поэтому вы получите вывод в конце операции. Это по замыслу.

Обходной путь, предложенный в ответе, заключался в использовании этого кода:

./program | ForEach-Object { Write-Host $_ $_ } | Set-Content program.log 

Альтернативная формулировка, чтобы попробовать, если вышеупомянутое не сработало:

./program | ForEach-Object { [Console]::WriteLine($_) [Console]::Out.Flush() $_ } | Set-Content program.log 

Таким образом, команда будет выглядеть так:

PowerShell -ExecutionPolicy Unrestricted "startmyserver | ForEach-Object { Write-Host $_; $_} | Set-Content server.log" 

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

Спасибо! Есть ли у вас какие-либо идеи, как (а) заставить эту запись записать как stdout, так и stderr, (б) добавить файл, который уже существует, вместо создания нового? Kidburla 5 лет назад 0
Смотрите [этот пост] (https://superuser.com/questions/273104/powershell-tee-questions). harrymc 5 лет назад 1
Спасибо, и мне удалось разрешить часть (b), используя `Add-Content` вместо` Set-Content` Kidburla 5 лет назад 0