Как я могу передать и отобразить вывод в командной строке Windows?

5951
Bob

У меня есть процесс, который мне нужно запустить в командном файле. Этот процесс производит некоторую продукцию. Мне нужно и вывести этот вывод на экран и отправить (передать) его в другую программу.

Метод bash использует tee:

echo 'ee' | tee /dev/tty | foo 

Есть ли аналог для Windows? Я счастлив использовать PowerShell при необходимости.

Есть teeпорты для Windows, но, похоже, нет эквивалента /dev/tty, что усложняет дело.


Конкретный вариант использования здесь: у меня есть программа (launch4j), которую мне нужно запустить, отображая вывод для пользователя. В то же время мне нужно уметь обнаруживать успех или неудачу в сценарии. К сожалению, эта программа не устанавливает код выхода, и я не могу заставить его сделать это. Мой текущий обходной путь заключается в том find, чтобы выполнить поиск в output ( launch4j config.xml | find "Successfully created") - однако это поглощает вывод, который мне нужно отобразить. Поэтому мне нужен какой-то способ как отобразить на экране, так и отправить выходные данные команде - и эта команда должна быть в состоянии установить ERRORLEVEL(она не может работать асинхронно). Это будет использоваться в скрипте сборки, который может быть запущен на разных компьютерах.

Для этого конкретного случая требуется что-то более легкое - я не могу установить дополнительные каркасы или интерпретаторы (например, perl, как предлагается в этом ответе ). Кроме того, любые коммерческие программы должны иметь лицензию, которая позволяет распространять.

4
Будет ли мой ответ более приемлемым, если я скомпилирую код и предоставлю ссылку на исполняемый файл? Я могу сделать это, если хотите, если у вас нет доступа к компилятору или вы не хотите делать это самостоятельно. BenjiWiebe 9 лет назад 0

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

1
Bob

One somewhat messy way I can think of is to use one of the ported tee programs, save to a temporary file and then test the file with find. However, the use of a temporary file may be undesirable.

If PowerShell is an option, it actually has a Tee-Output cmdlet. It's not quite as direct as the bash example, but it does have a -Variable option to save the output into a variable, which can then be searched:

# save result in $LastOutput and also display it to the console echo "some text" | Tee-Output -Variable LastOutput # search $LastOutput for a pattern, using Select-String # instead of find to keep it within PowerShell $Result = $LastOutput | Select-String -Quiet "text to find" # $Result should contain either true or false now # this is the equivalent of batch "if errorlevel 1" if ($Result -eq $True) { # the string exists in the output } 

To answer the more general question, it is also possible to pipe the variable into any other program, which will then set $LastExitCode. As a one-liner that can be called from the basic command line: powershell -c "echo text | Tee-Object -Variable Result; $Result | foo"

Я все еще ищу способ сделать это без временного файла в базовой (не PowerShell) командной строке, если это возможно. Bob 9 лет назад 0
На * nix я всегда `tee` к` stderr`; Есть ли способ `tee` для` stderr` и `stdout` в PowerShell, или Windows / PowerShell не имеет такой концепции? BenjiWiebe 9 лет назад 0
@BenjiWiebe `/ dev / stderr`, правильно? Насколько я знаю, этого не существует в Windows. Что-то с именованными каналами было бы возможно, но я стараюсь не писать программу только для этой цели! Bob 9 лет назад 0
Программно говоря, `/ dev / stderr` - это концепция ядра, которая перенаправляет материал в файловый дескриптор для` stderr`. Разве в Windows не было бы способа перенаправить на `stderr` (НЕ` / dev / stderr`)? BenjiWiebe 9 лет назад 1
Смотрите мой ответ для объяснения того, что я думал (и это могло бы работать!) BenjiWiebe 9 лет назад 0
@ BenjiWiebe Ах, да, я имел в виду, что в Windows нет прямого эквивалента, который представляет файловые дескрипторы как файлы устройств. Написание программы, которая просто печатает на них, работало бы, да. Bob 9 лет назад 0
Вы хотите сказать, что мой код действительно будет работать ** !? :) BenjiWiebe 9 лет назад 0
@ BenjiWiebe Да, похоже, это должно работать. Сейчас я просто собираюсь использовать свой сценарий PowerShell, поскольку это избавляет меня от необходимости добавлять дополнительный двоичный файл, но у меня есть преимущество для хорошего решения :) Bob 9 лет назад 0
В powershell вы можете сделать перенаправление `*> & 1` перенаправит весь вывод в 'stdout' Eris 9 лет назад 0
1
BenjiWiebe

You could try compiling this code and using it like: echo something | mytee | foo.
I don't know if it will work, since I don't know how Windows deals with stderr/stdout, but it might work.

#include <stdio.h> int main() { int c; while((c = fgetc(stdin)) != EOF) { printf("%c", c); fprintf(stderr, "%c", c); } return 0; } 
1
Shawn Melton

Why not just execute the command in PowerShell using Invoke-Command and capture the results into a variable. You search the variable for your results if they are there, do something, and then display all the output to the console.

Test file to capture output from is just notepad with the following text (C;\Temp\OutputTest.txt):

blahlbalsdfh abalkshdiohf32iosknfsda afjifwj93f2ji23fnsfaijfafds fwjifej9f023f90f3nisfadlfasd fwjf9e2902fjf3jifdsfajofsda jfioewjf0990f Successfully Created fsjfd9waf09jf329j0f3wjf90awfjw0afwua9 

In your case though you would call your command as something like {& "Launch4j" config.xml} I believe, but for my example:

Invoke-Command -ScriptBlock | foreach { $_; if ($_ -match "successfully created") {$flag = $true} } if ($flag) { "do whatever" } 
Это именно то, что я сделал, и то, что я описал в своем самоответе ... Добавляет ли этот ответ больше информации? Bob 9 лет назад 0
Ах, я вижу, процесс немного отличается (не использует `Tee-Object` напрямую, вместо этого вручную печатает вывод позже). Затем, я полагаю, один из недостатков этого подхода заключается в том, что он должен захватывать весь вывод и затем отображать его за один раз - это означает, что пользователь не увидит никакого вывода во время выполнения процесса, только после его завершения. Это приемлемо для краткосрочных задач, но совсем не хорошо для более длительных. Bob 9 лет назад 0
Отредактировано, чтобы просто выводить каждую строку и проверять одновременно, устанавливая флаг, если он найдет ваше сообщение. Поскольку ваша команда выполняется на основе сообщения, она не будет выполняться до тех пор, пока не будет завершен вывод, что, как указывает ваш вопрос, не может выполняться асинхронно. Однако если вы можете использовать Start-Job в PowerShell для выполнения его вне текущего процесса, если вам это нужно, то после завершения вывода проверьте состояние задания с помощью Get-Job. Shawn Melton 9 лет назад 0
0
AFH

I would recommend TCC/LE from JP Software: it implements many of the features of bash, including TEE, in CMD-compatible syntax. In your example it would be:

echo ee|tee con:|foo 

I tested with the following command

for /l %n in (1,1,10) do ( echo %n %+ delay)|tee con:|nl. 

Here NL is a program which gives a numbered listing, and the output was interspersed unnumbered and numbered lines. The 1 second delay allowed me to see that both the console and the pipe reader were receiving lines simultaneously.

The LE version is free for private use.

К сожалению, для моей конкретной задачи это уже слишком. Если бы я хотел использовать слой эмуляции POSIX, я бы просто использовал MSYS или cygwin. Кроме того, сам `tee` не помогает - это возможность перенаправить на tty или устройство вывода, как если бы это был файл, что обеспечивает POSIX, а не команда` tee`. Bob 9 лет назад 0
TCC может сделать именно это: `echo ee | tee con: | foo` - я протестировал с помощью следующей команды` for / l% n в (1,1,10) do (echo% n% + delay) | tee con: | nl`. Здесь NL - программа, которая выдает нумерованный список, а на выходе получаются перемежающиеся ненумерованные и нумерованные строки. Задержка в 1 секунду позволила мне увидеть, что и консоль, и устройство чтения каналов одновременно получали линии. Извините, вы чувствуете, что это излишне: я не был бы без TCC. AFH 9 лет назад 0
Правильно - было бы замечательно, если бы вы включили это в свой ответ (не сразу очевидно, что он предоставляет какой-то способ ссылки на консоль). Для моего случая все еще излишне, так как я пытаюсь создать сценарий сборки, который будет привязан к контролю версий для использования другими людьми, поэтому я хотел бы свести к минимуму стороннее программное обеспечение, которое мне нужно было бы объединять (если лицензия даже позволяет Redis). Небольшой двоичный файл, такой как ответ Бенджи, является приемлемым, и интерпретатор команд, который мне нужно установить, слишком большой. Это может быть полезно для других людей. Bob 9 лет назад 0
Хорошая точка зрения. Я обновил свой ответ, как вы предлагаете, и я вижу, что решение Бенджи могло бы хорошо соответствовать вашим конкретным потребностям, но я подумал, что протестирую его, и обнаружил, что вам нужно добавить `fflush (NULL);` после строка _fprintf () _, чтобы увидеть результат в режиме реального времени. Если вы находитесь в коммерческой среде, вы не можете использовать TCC без покупки соответствующих лицензий. AFH 9 лет назад 0
0
Keltari

You could rewrite your batch file as a PowerShell script. PowerShell has Tee-Object (aliased as Tee).

Parameter Set: File Tee-Object [-FilePath] [-Append] [-InputObject ] [ ]

Parameter Set: LiteralFile Tee-Object -LiteralPath [-InputObject ] [ ]

Parameter Set: Variable Tee-Object -Variable [-InputObject ] [ ]

Да, это то, что я в итоге делал, с процессом, описанным в самоответе. Добавляет ли этот ответ дополнительную информацию? Bob 9 лет назад 0
-1
Jet

Просто поместите это в командный файл (скажем так echox.bat):

@echo off echo %1 echo %1|%2 

Затем назовите эту партию так:

echox 'c:\' dir 

Он распечатает c:\и распечатает вывод dir c:\.

ПРИМЕЧАНИЕ: поскольку мы используем %1, %2параметры должны быть переданы без пробелов или внутри " "и ' '.

При применении к произвольным задачам команда будет выполнена дважды, первый раз напечатав вывод на консоли, второй раз отправив трубку к цели. Это может не сработать, например, если команда сама изменяет состояние файлов и т. Д. На жестком диске. Thomas Weller 9 лет назад 1
@ThomasW, он не выполнит команду дважды. Как видите, первый `echo% 1` просто выведет на экран параметр`% 1`, а второй `echo` отправит параметр`% 1` в программу `% 2`. Конечно, он имеет некоторые ограничения, но в целом решает проблему. Jet 9 лет назад 0