Jak przekierować wyjście do pliku i standardowego wyjścia


988

W bashu wywołanie foowyświetlałoby dane wyjściowe z tego polecenia na standardowym wyjściu.

Wywołanie foo > outputprzekieruje dane wyjściowe z tej komendy do określonego pliku (w tym przypadku „wynik”).

Czy istnieje sposób przekierowania wyjścia do pliku i wyświetlania go na standardowym wyjściu?


3
Jeśli ktoś właśnie znalazł się tutaj, szukając wyjścia błędu do pliku, spójrz na - unix.stackexchange.com/questions/132511/…
Murphy

2
Uwaga na temat terminologii: po uruchomieniu foo > outputdane zapisywane na stdout, a stdout to plik o nazwie output. Oznacza to, że zapis do pliku jest zapisywany na standardowe wyjście. Pytasz, czy można napisać zarówno na standardowe wyjście, jak i na terminal.
William Pursell

2
@WilliamPursell Nie jestem pewien, czy twoje wyjaśnienie poprawia rzeczy :-) A co z tym: OP pyta, czy możliwe jest skierowanie standardowego programu wywoływanego zarówno do pliku, jak i standardowego programu wywołującego (ten drugi jest standardowym standardem wywoływanego programu dziedzicz, jeśli nic specjalnego nie zostało zrobione, tj. terminal, jeśli program wywołujący jest interaktywną sesją bash). Być może chcą również podobnie pokierować stderr wywoływanego programu („każde wyjście z tego polecenia” może być rozsądnie interpretowane jako obejmujące stderr).
Don Hatch,

Odpowiedzi:


1377

Polecenie ma nazwę tee:

foo | tee output.file

Na przykład, jeśli zależy Ci tylko na standardowym:

ls -a | tee output.file

Jeśli chcesz dołączyć stderr, wykonaj:

program [arguments...] 2>&1 | tee outfile

2>&1przekierowuje kanał 2 (stderr / błąd standardowy) na kanał 1 (wyjście standardowe / standardowe wyjście), tak że oba są zapisywane jako standardowe wyjście. Jest również kierowany do podanego pliku wyjściowego od teepolecenia.

Ponadto, jeśli chcesz dołączyć do pliku dziennika, użyj tee -ajako:

program [arguments...] 2>&1 | tee -a outfile

173
Jeśli OP chce przekierować „wszystkie dane wyjściowe”, musisz także pobrać stderr: „ls -lR / 2> & 1 | tee output.file”
James Brady

45
@evanmcdonnal Odpowiedź nie jest zła, może nie być wystarczająco szczegółowa lub kompletna w zależności od twoich wymagań. Z pewnością istnieją warunki, w których możesz nie chcieć, aby stderr jako część wyniku był zapisywany w pliku. Kiedy odpowiedziałem na to 5 lat temu, założyłem, że OP chce tylko stdout, ponieważ wspomniał o stdout w temacie postu.
Zoredache,

3
Ach, przepraszam, mogłem być trochę zdezorientowany. Kiedy spróbowałem, po prostu nie otrzymałem danych wyjściowych, być może wszystko zaczęło się kręcić.
evanmcdonnal

38
Użyj -aargumentu, teeaby dołączyć treść output.file, zamiast nadpisywać:ls -lR / | tee -a output.file
kazy

16
Jeśli używasz $?później, zwróci kod stanu tee, który prawdopodobnie nie jest tym, czego chcesz. Zamiast tego możesz użyć ${PIPESTATUS[0]}.
LaGoutte

501
$ program [arguments...] 2>&1 | tee outfile

2>&1zrzuca strumienie stderr i stdout. tee outfilepobiera otrzymany strumień i zapisuje go na ekranie oraz w pliku „outfile”.

Tego prawdopodobnie szuka większość ludzi. Prawdopodobną sytuacją jest to, że jakiś program lub skrypt ciężko pracuje przez długi czas i generuje wiele wyników. Użytkownik chce okresowo sprawdzać postęp, ale chce również, aby dane wyjściowe były zapisywane w pliku.

Problem (szczególnie przy mieszaniu strumieni stdout i stderr) polega na tym, że program polega na opróżnianiu strumieni. Jeśli na przykład wszystkie zapisy na standardowe wyjście nie zostaną usunięte, ale wszystkie zapisy na standardowe zostaną wyczyszczone, to skończy się to chronologicznie w pliku wyjściowym i na ekranie.

Jest to również złe, jeśli program wyświetla tylko 1 lub 2 linie co kilka minut, aby zgłosić postęp. W takim przypadku, jeśli dane wyjściowe nie zostałyby wyczyszczone przez program, użytkownik nawet nie widziałby żadnych danych wyjściowych na ekranie przez wiele godzin, ponieważ żadne z nich nie zostałoby przepchnięte przez rurę przez wiele godzin.

Aktualizacja: program unbuffer, będący częścią expectpakietu, rozwiąże problem buforowania. Spowoduje to, że stdout i stderr będą natychmiast zapisywać na ekranie i pliku i utrzymywać je w synchronizacji podczas łączenia i przekierowywania do tee. Na przykład:

$ unbuffer program [arguments...] 2>&1 | tee outfile

7
Czy ktoś wie o „unbuffer” dla OSX?
John Mee,

7
Jeśli nie możesz użyć rozpakowywania, GNU coreutils zawiera narzędzie o nazwie stdbuff, które może być użyte do zapobiegania buforowaniu wyjścia w ten sposób$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter

1
Jeśli używasz systemu OS X, w większości przypadków korzystanie z buforowania jest nieco łatwiejsze, ale nie, jeśli chcesz przekazywać sygnały do ​​uruchomionego polecenia. Mój komentarz był bardziej skierowany do użytkowników Linuksa, gdzie coreutils najprawdopodobniej jest domyślnie instalowany. @ Ethan, zobacz tę odpowiedź, jeśli masz wątpliwości co do składni stdbuf: stackoverflow.com/a/25548995/942781
Peter

3
Zauważ, że pythonma wbudowaną opcję, -uktóra rozpakowuje dane wyjściowe.
fabian789

1
Absolutny ratownik do szkolenia modeli ML, w których chcę się logować bez dodatkowego kodu, ale także zobaczyć wynik w godzinach / dniach potrzebnych do uruchomienia, dziękuję!
rokoko

126

Innym sposobem, który działa dla mnie jest

<command> |& tee  <outputFile>

jak pokazano w instrukcji gnu bash

Przykład:

ls |& tee files.txt

Jeśli użyto „| &”, błąd standardowy polecenia 1 , oprócz standardowego wyjścia , jest podłączony do standardowego wejścia polecenia 2 przez potok; jest skrótem dla 2> i 1 |. To niejawne przekierowanie standardowego błędu na standardowe wyjście jest wykonywane po wszelkich przekierowaniach określonych przez polecenie.

Aby uzyskać więcej informacji, zobacz przekierowanie


10
Jeśli używasz $?później, zwróci kod stanu tee, który prawdopodobnie nie jest tym, czego chcesz. Zamiast tego możesz użyć ${PIPESTATUS[0]}.
LaGoutte

1
Ta metoda odrzuca kolorowe wyjście konsoli, jakieś pomysły?
shakram02

Spróbuj: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini

17

Możesz przede wszystkim użyć rozwiązania Zoredache , ale jeśli nie chcesz nadpisywać pliku wyjściowego, powinieneś napisać tee z opcją -a w następujący sposób:

ls -lR / | tee -a output.file

11

Coś do dodania ...

Rozpakowywanie pakietów ma problemy z obsługą niektórych pakietów w wydaniach fedora i redhat unix.

Odkładając na bok kłopoty

Obserwowanie działało dla mnie

bash myscript.sh 2>&1 | tee output.log

Dziękuję ScDF & matthew twoi wejścia uratował mnie dużo czasu ..



3

Dodatkowa odpowiedź, ponieważ ten przypadek użycia przywiózł mnie tutaj:

W przypadku, gdy musisz to zrobić jako inny użytkownik

echo "some output" | sudo -u some_user tee /some/path/some_file

Zauważ, że echo pojawi się tak jak ty, a zapis pliku nastąpi jako „some_user”, co NIE zadziała, jeśli uruchomisz echo jako „some_user” i przekierujesz dane wyjściowe za pomocą >> „some_file”, ponieważ nastąpi przekierowanie pliku jak ty.

Wskazówka: tee obsługuje także append z flagą -a, jeśli chcesz zastąpić linię w pliku innym użytkownikiem, możesz uruchomić sed jako pożądany użytkownik.


2

< command > |& tee filename # spowoduje to utworzenie pliku „nazwa pliku” ze statusem polecenia jako treści. Jeśli plik już istnieje, usunie istniejącą zawartość i zapisze status polecenia.

< command > | tee >> filename # to dołącza status do pliku, ale nie drukuje statusu polecenia na standard_output (screen).

Chcę wydrukować coś za pomocą „echa” na ekranie i dołączyć dane echa do pliku

echo "hi there, Have to print this on screen and append to a file" 

1

Możesz to zrobić dla całego skryptu, używając czegoś takiego na początku skryptu:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

To przekierowuje zarówno wyjścia stderr, jak i stdout do pliku o nazwie mylogfile i pozwala, aby wszystko poszło w tym samym czasie .

Używa się kilku głupich sztuczek:

  • użyj execbez polecenia, aby skonfigurować przekierowania,
  • używać teedo powielania wyników,
  • zrestartuj skrypt z pożądanymi przekierowaniami,
  • użyj specjalnego pierwszego parametru (prostego NULznaku określonego w $'string'specjalnej notacji bash), aby określić, że skrypt zostanie zrestartowany (w oryginalnej pracy nie można użyć równoważnego parametru),
  • spróbuj zachować oryginalny status wyjścia podczas ponownego uruchamiania skryptu za pomocą pipefailopcji.

Brzydkie, ale przydatne w niektórych sytuacjach.


-13

tee jest do tego idealna, ale to też zadziała

ls -lr / > output | cat output

10
Jest to błąd, jeśli dane wyjściowe jeszcze nie istnieją i nie robią tego, co chcesz, jeśli tak, ogólnie rzecz biorąc, jest to nonsensowne. Być może miałeś na myśli „;” zamiast „|” ?
Robert Gamble

6
Nawet jeśli użyjesz a ;, wyjście będzie znacznie opóźnione podczas powolnego polecenia.
Brad Koch
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.