Jak wywołać echo i wysłać dane wyjściowe konsoli do pliku w skrypcie nietoperza?

136

Mam skrypt wsadowy, który wykonuje zadanie i wysyła dane wyjściowe do pliku tekstowego. Czy istnieje sposób, aby dane wyjściowe były wyświetlane również w oknie konsoli?

Na przykład:

c:\Windows>dir > windows-dir.txt

Czy jest sposób, aby dane wyjściowe dirwyświetlania w oknie konsoli, a także umieścić je w pliku tekstowym?

JamesEggers
źródło
Oto wyjaśnienie przekierowań, które możesz wprowadzić, i kilka przykładów. <br> Mam nadzieję, że to pomoże :)
emoSTN
Proszę zauważyć, @Vadzim, że pytanie zadane 2 lutego 2009 o 16:38 nie może być traktowane jako duplikat pytania zadanego prawie trzy miesiące później 28 kwietnia 2009 o 06:32.
Compo

Odpowiedzi:

216

Nie, nie możesz z czystym przekierowaniem.
Ale z niektórymi sztuczkami (jak tee.bat ) możesz.

Staram się trochę wyjaśnić przekierowanie.

Przekierowujesz jeden z dziesięciu strumieni za pomocą > plik lub <plik.
Nie ma znaczenia, czy przekierowanie następuje przed lub po poleceniu, więc te dwie linie są prawie takie same.

dir > file.txt
> file.txt dir

Przekierowanie w tym przykładzie jest tylko skrótem do 1> , co oznacza, że ​​zostanie przekierowany strumień 1 (STDOUT).
Możesz więc przekierować dowolny strumień, poprzedzając liczbę, taką jak 2> err.txt, a także możesz przekierować wiele strumieni w jednej linii.

dir 1> files.txt 2> err.txt 3> nothing.txt

W tym przykładzie „standardowe wyjście” zostanie umieszczone w plikach.txt, wszystkie błędy w err.txt, a strumień 3 - do nic.txt (DIR nie używa strumienia 3).
Strumień0 to STDIN
Strumień1 to STDOUT
Strumień2 to STDERR
Strumienie 3-9 nie są używane

Ale co się stanie, jeśli spróbujesz wielokrotnie przekierować ten sam strumień?

dir > files.txt > two.txt

„Może być tylko jeden” i zawsze jest ostatni!
Czyli jest równe dir> two.txt

Ok, jest jeszcze jedna możliwość, przekierowanie strumienia do innego strumienia.

dir 1>files.txt 2>&1 

2> & 1 przekierowuje stream2 do stream1, a 1> files.txt przekierowuje wszystko do files.txt .
Kolejność jest tutaj ważna!

dir ... 1>nul 2>&1
dir ... 2>&1 1>nul

są różne. Pierwsza z nich przekierowuje wszystkie (STDOUT i STDERR) do NUL,
ale druga linia przekierowuje STDOUT do NUL i STDERR do „pustego” STDOUT.

Podsumowując, jest oczywiste, dlaczego przykłady Otávio Décio i andynormancx nie działają.

command > file >&1
dir > file.txt >&2

Obaj próbują przekierować stream1 dwa razy, ale „może być tylko jeden” i zawsze jest to ostatni.
Więc masz

command 1>&1
dir 1>&2

W pierwszym przykładzie przekierowanie stream1 do stream1 jest niedozwolone (i niezbyt przydatne).

Mam nadzieję, że to pomoże.

jeb
źródło
24
Więc jest to niemożliwe z natywną powłoką systemu Windows
fantastyczny
7
@fantastory To możliwe, zobacz to świetne rozwiązanie partii dbenham systemu Windows: polecenie „tee”
jeb
97
Nie mogę uwierzyć, że po prostu przeczytałem cały ten post, aby dowiedzieć się, że całość można podsumować jako „Nie”.
Charles McKelvey
1
A co z drugim mechanizmem „obsługi duplikacji”? Eksperymentowałem z 3<&2(uwaga na LT zamiast GT), a potem 3>errors.txt. Ale to się źle skończyło - wszystkie następne wyjście stderr zostało przechwycone errors.txt(to znaczy - także z innych poleceń!).
Tomasz Gandor
Możesz jednak użyć for /f "delims=" %%v in ('dir') do echo %%v>>file.txt.
scriptmastere02
32

Po prostu użyj wersji UNIX tee polecenia systemu Windows (znalezionej na stronie http://unxutils.sourceforge.net ) w następujący sposób:

mycommand > tee outpu_file.txt

Jeśli potrzebujesz również wyjścia STDERR, użyj następującego. Łączy wyjście StdErr do standardowe wyjście (strumień podstawowy).
2>&1

mycommand 2>&1 | tee output_file.txt
atn
źródło
3
Obiekt Tee programu PowerShell oferuje podobną funkcjonalność. Get-Process | Tee-Object -file c: \ scripts \ test.txt
Kevin Obee
Wypróbowałem to w PowerShell i zwykłej powłoce. 1>tee a.txtprzekieruje standardowe wyjście do pliku o nazwie teezamiast wywoływania teepolecenia. Czy ktoś może potwierdzić, że ta odpowiedź działa dla niego?
mafu
@mafu Mogę to potwierdzić.
Cerno
@mafu Powyższa odpowiedź jest nieco błędna. Musisz użyć potoku „|” zamiast „>” w górnym przykładzie. Co dziwne, w tym przypadku kolejność wyjścia STDOUT i STDERR została pomieszana w linii poleceń. Jednak dolny przykład działa idealnie dla mnie.
Cerno
Również pobieranie sourceforge zostało zepsute. Znalazłem alternatywnego hosta tutaj: wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (Uniwersytet w Monachium)
Cerno
9

Jeśli nie potrzebujesz danych wyjściowych w czasie rzeczywistym (np. Gdy program je zapisuje), możesz dodać

type windows-dir.txt

po tej linii.

Mark Pim
źródło
i w tej samej linii (użyteczny w wierszu): dir > windows-dir.txt & type windows-dir.txt. Odnosi się to także do bloków: ( echo %date% <NL> echo %username% <NL> echo %time% <NL> pause>CON )>test.txt & type test.txt. Jednakże, jeśli wyjście jest wymagane w czasie rzeczywistym, można użyć np Windows port tee narzędzie, które ...
mousio
7

Rozwiązaniem, które zadziałało, było: dir> a.txt | wpisz a.txt .

NSPKUWCExi2pr8wVoGNk
źródło
2
Działa to z poleceniem o niskiej wydajności. Z dużym poleceniem wyjściowym nie działa, ponieważ pokazuje tylko pierwszy bufor. Prosi o dane wyjściowe w czasie rzeczywistym, jednocześnie zapisując je w pliku dziennika.
NetVicious
Byłoby problematyczne, gdybyś użył >> zamiast>
Nime Cloud
6

Tak, istnieje sposób na pokazanie wyjścia pojedynczego polecenia na konsoli (ekranie) oraz w pliku. Na swoim przykładzie użyj ...

@ECHO OFF
FOR /F "tokens=*" %%I IN ('DIR') DO ECHO %%I & ECHO %%I>>windows-dir.txt

Szczegółowe wyjaśnienie:

Plik FORPolecenie przetwarza dane wyjściowe polecenia lub tekst do zmiennej, która może się odwoływać wielokrotnie.

Polecenie, takie jak DIR /B, należy ująć w pojedyncze cudzysłowy, jak pokazano w przykładzie poniżej. Zastąp DIR /Btekst żądanym poleceniem.

FOR /F "tokens=*" %%I IN ('DIR /B') DO ECHO %%I & ECHO %%I>>FILE.TXT

Aby wyświetlić tekst, umieść go w podwójnych cudzysłowach, jak pokazano w przykładzie poniżej.

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO ECHO %%I & ECHO %%I>>FILE.TXT

... i z zawijaniem linii ...

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO (
  ECHO %%I & ECHO %%I>>FILE.TXT
)

Jeśli zdarzają się sytuacje, w których chcesz, aby dane wyjściowe były tylko na konsoli (ekranie), a innym razem wysyłane tylko do pliku, a innym razem wysyłane do obu, określ klauzulę „DO” pętli FOR za pomocą zmiennej, jak pokazano poniżej za pomocą %TOECHOWHERE%.

@ECHO OFF
FOR %%I IN (TRUE FALSE) DO (
  FOR %%J IN (TRUE FALSE) DO (
    SET TOSCREEN=%%I & SET TOFILE=%%J & CALL :Runit)
)
GOTO :Finish

:Runit
  REM Both TOSCREEN and TOFILE get assigned a trailing space in the FOR loops
  REM above when the FOR loops are evaluating the first item in the list,
  REM "TRUE".  So, the first value of TOSCREEN is "TRUE " (with a trailing
  REM space), the second value is "FALSE" (no trailing or leading space).
  REM Adding the ": =" text after "TOSCREEN" tells the command processor to
  REM remove all spaces from the value in the "TOSCREEN" variable.
  IF "%TOSCREEN: =%"=="TRUE" (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=On screen, and in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I & ECHO %%I>>FILE.TXT"
        ) ELSE (
          SET TEXT=On screen, not in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I"
      )
    ) ELSE (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=Not on screen, but in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>>FILE.txt"
        ) ELSE (
          SET TEXT=Not on screen, nor in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>NUL"
      )
  )
  FOR /F "tokens=*" %%I IN ("%TEXT%") DO %TOECHOWHERE:~1,-1%
GOTO :eof

:Finish
  ECHO Finished [this text to console (screen) only].
  PAUSE
Zadziwiać
źródło
Zamiast tego powinieneś użyć delims=.
scriptmastere02
3
command > file >&1
Otávio Décio
źródło
Jest szybsze, gdy nie wypisujesz danych na ekranie, ponieważ nie wypełniasz bufora bzdurami, ale raczej pozwalasz na uruchomienie zadania wsadowego. jeśli debugujesz, nie użyłbym składni> pliku.
Losowy programista
@andynormancx yup zapomniał wpisać to zamiast wycinania i wklejania z CMD.
Losowy programista
Nie mogłem uzyskać składni do pracy w wierszu poleceń systemu Windows i zamiast tego poszedłem z poleceniem typu.
JamesEggers
& 2 działa, ale plik nie jest teraz tworzony podczas testowania.
JamesEggers
5
jeśli zrobię "dir> file.txt> & 2" plik.txt nie jest tworzony. Dane wyjściowe katalogu są wyświetlane w konsoli, ale plik nie jest tworzony. Plik jest tworzony, gdy nie ma znaku „> & 2”.
JamesEggers
2

Jeśli chcesz dołączyć zamiast zastępować plik wyjściowy, możesz użyć

dir 1>> files.txt 2>> err.txt

lub

dir 1>> files.txt 2>>&1
Jochen
źródło
2

Moja opcja była taka:

Utwórz podprogram, który przyjmuje wiadomość i automatyzuje proces wysyłania jej zarówno do konsoli, jak i do pliku dziennika.

setlocal
set logfile=logfile.log

call :screenandlog "%DATE% %TIME% This message goes to the screen and to the log"    

goto :eof

:screenandlog
set message=%~1
echo %message% & echo %message% >> %logfile%
exit /b

Jeśli dodasz zmienną do wiadomości, pamiętaj, aby usunąć zawarte w niej cudzysłowy przed wysłaniem jej do podprogramu, w przeciwnym razie może to wkręcić twoją partię. Oczywiście działa to tylko w przypadku echa.

JPZ
źródło
WOW, TAK! Naprawdę to lubię!! Jednak wprowadziłem trzy zmiany, mam nadzieję, że Ci się podobają. 1) Używam setlocal enabledelayedexpansionzamiast tylko setlocal 2) Używam opóźnionego rozwinięcia dla zmiennej logfile, więc >> !logfile!zamiast >> %logfile%w podprogramie. W ten sposób działa, gdy jest wywoływana z bloku kodu (jak w instrukcji if). 3) Usunąłem wiersz „ustaw wiadomość”, ponieważ nie ma potrzeby stosowania dodatkowej zmiennej. Mamy już to w, $~1więc mam echo $~1dla obu poleceń echa.
Nate
2

Zrobiłem prostą konsolę C #, która może obsługiwać dane wyjściowe w czasie rzeczywistym zarówno do ekranu cmd, jak i dziennika

class Tee
{
    static int Main(string[] args)
    {
        try
        {
            string logFilePath = Path.GetFullPath(args[0]);

            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                for (int value; (value = Console.In.Read()) != -1;)
                {
                    var word = Char.ConvertFromUtf32(value);
                    Console.Write(word);
                    writer.Write(word);
                }
            }
        }
        catch (Exception)
        {
            return 1;
        }
        return 0;
    }
}

Użycie pliku wsadowego jest takie samo, jak w przypadku korzystania z systemu Unix tee

foo | tee xxx.log

A oto repozytorium zawierające Tee.exe na wypadek, gdybyś nie miał narzędzia do kompilacji https://github.com/iamshiao/Tee

Circle Hsiao
źródło
1

Podoba mi się odpowiedź atn, ale nie było to dla mnie tak trywialne, jak pobranie wintee , które jest również open source i zapewnia tylko funkcjonalność koszulki (przydatne, jeśli chcesz tylko tee, a nie cały zestaw narzędzi unixowych). Dowiedziałem się o tym z odpowiedzi davora na Wyświetlanie wyjścia wiersza poleceń systemu Windows i przekierowanie go do pliku , w którym znajduje się również odniesienie do narzędzi unixowych.

szałwia
źródło
0

Rozwiązanie dostarczone przez „Tomasa R” działa idealnie na pytanie OP i jest dostępne natywnie.

Spróbuj: chkdsk c:> output.txt | wpisz output.txt

Wynik tego polecenia zawiera procent ukończenia, który jest seryjnie wysyłany do pliku, dlatego będzie wyglądał nieco niechlujnie (tj. Tekst będzie dołączany w miarę postępu). Nie dotyczy to bitów wysyłanych do STDOUT (ekran). Tak by było, gdybyś wykonał to samo polecenie bez przekierowania.

J0N
źródło
-3

Myślę, że chcesz czegoś podobnego do tego:

echo Your Msg> YourTxtFile.txt

Lub jeśli chcesz nową linię:

echo Your Msg>> YourTxtFile.txt

Te polecenia świetnie nadają się do dzienników.

Uwaga: czasami powoduje to usterkę i zastąpienie całego pliku tekstowego na moim komputerze.

Kolejna uwaga: jeśli plik nie istnieje, utworzy plik.

Gladius125
źródło
1
nie, OP chciał mieć dane wyjściowe do pliku i na ekranie. Twój po prostu pisze do pliku. (I >jest przeznaczony do nadpisywania pliku. Użyj, >>aby dołączyć )
Stephan