jak wyprowadzać tekst na ekran i plik w skrypcie powłoki?


49

Obecnie mam skrypt powłoki, który rejestruje wiadomości do pliku dziennika takiego jak ten:

log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command

Podczas wykonywania tego skryptu nie ma danych wyjściowych do ekranu, a ponieważ łączę się z serwerem za pomocą kitu, muszę otworzyć inne połączenie i wykonać polecenie „tail -f log_file_path.log”, ponieważ nie mogę zakończyć działania skrypt i chcę zobaczyć dane wyjściowe w czasie rzeczywistym.

Oczywiście chcę, aby wiadomości tekstowe były drukowane na ekranie i do pliku, ale chciałbym to zrobić w jednym wierszu, a nie w dwóch wierszach, z których jeden nie ma przekierowania do pliku.

Jak to osiągnąć?

Odpowiedzi:


71

To działa:

command | tee -a "$log_file"

teezapisuje dane wejściowe do pliku (użyj -ado dodawania zamiast nadpisywania), a także kopiuje dane wejściowe na standardowe wyjście.


8

Możesz użyć tutaj-doc i. pozyskaj go, aby uzyskać wydajny, przyjazny dla POSIX ogólny model kolektora.

. 8<<-\IOHERE /proc/self/fd/8

command
 
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE

Kiedy otworzysz heredoc, zasygnalizujesz powłoce token wejściowy IOHERE, że powinien przekierować swoje wejście do określonego deskryptora pliku, dopóki nie napotka drugiego końca tokena ograniczającego. Rozejrzałem się, ale nie widziałem wielu przykładów użycia numeru fd przekierowania, jak pokazano powyżej w połączeniu z operatorem heredoc, chociaż jego użycie jest jasno określone w podstawowych wytycznych POSIX dotyczących poleceń powłoki. Większość ludzi po prostu wskazuje to na standardowe wejście i strzela, ale uważam, że w ten sposób skryptlety źródłowe mogą uwolnić standardowe wejście i standardowe aplikacje nie mogą narzekać na zablokowane ścieżki wejścia / wyjścia.

Zawartość heredoc jest przesyłana strumieniowo do określonego deskryptora pliku, który z kolei jest interpretowany jako kod powłoki i wykonywany przez. wbudowane, ale nie bez określonej ścieżki. . Jeśli ścieżka / proc / self sprawia ci kłopotów, spróbuj / dev / fd / n lub / proc / $$. Ta sama metoda działa na rurach, nawiasem mówiąc:

cat ./*.sh | . /dev/stdin

Jest prawdopodobnie co najmniej tak nierozsądny, jak się wydaje. Możesz zrobić to samo z sh, oczywiście, ale celem. Jest wykonanie w bieżącym środowisku powłoki, co jest prawdopodobnie tym, czego chcesz, i, w zależności od twojej powłoki, jest znacznie bardziej prawdopodobne, aby pracować z heredoc niż ze standardową anonimową potokiem.

W każdym razie, jak zapewne zauważyłeś, wciąż nie odpowiedziałem na twoje pytanie. Ale jeśli się nad tym zastanowić, w ten sam sposób, w jaki heredoc przesyła strumieniowo cały kod do pliku .s, zapewnia również pojedynczy, prosty punkt:

. 5<<EOIN /dev/fd/5 |\ 
    tee -a ./log.file | cat -u >$(tty)
script
 
more script
EOIN

Więc wszystkie terminale stdout z dowolnego kodu wykonanego w twoim heredoc są wysyłane z. oczywiście i można go łatwo zdjąć z jednej rury. Dołączyłem niebuforowane wołanie kota, ponieważ nie jestem pewien, co do obecnego kierunku wyjścia, ale prawdopodobnie jest ono zbędne (prawie na pewno jest tak napisane), a rurociąg może prawdopodobnie skończyć się na tee.

W drugim przykładzie możesz również zakwestionować brakujący cytat z odwrotnym ukośnikiem. Ta część jest ważna do zrozumienia przed przystąpieniem i może dać ci kilka pomysłów na temat jej wykorzystania. Cytowany ogranicznik heredoc (do tej pory używaliśmy IOHERE i EOIN, a pierwszy cytowany z odwrotnym ukośnikiem, chociaż „pojedyncze” lub „podwójne” cudzysłowy służyłyby temu samemu celowi) zablokuje powłoce wykonywanie jakiegokolwiek rozszerzenia parametrów na zawartość, ale niecytowany ogranicznik pozostawi jego zawartość otwartą do rozbudowy. Konsekwencje tego, kiedy twój heredok jest. źródła są dramatyczne:

. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)} 
HD
echo $vars
> 4,8,12 
echo $var1 $var51
> 4 104

Ponieważ nie zacytowałem ogranicznika heredoc, powłoka rozszerzyła zawartość, czytając ją i przed podaniem wynikowego deskryptora pliku. wykonać. Zasadniczo spowodowało to dwukrotne przeanalizowanie poleceń - w każdym razie poleceń rozwijalnych. Ponieważ odwrócony ukośnik zacytowałem rozszerzenie parametru $ vars, powłoka zignorowała swoją deklarację przy pierwszym przejściu i usunęła tylko odwrotny ukośnik, aby cała rozwinięta zawartość printf mogła być oceniona przez zero, kiedy. pozyskałem skrypt w drugim przebiegu.

Ta funkcjonalność jest dokładnie tym, co może zapewnić niebezpieczna wbudowana powłoka eval, nawet jeśli cytowanie jest znacznie łatwiejsze w heredoc niż w eval, i może być równie niebezpieczne. O ile nie zaplanujesz go dokładnie, prawdopodobnie najlepiej jest przyzwyczaić się do ogranicznika „EOF”. Tylko mówię.

EDYCJA: Eh, patrzę wstecz i myślę, że to trochę za dużo. Jeśli WSZYSTKO, co musisz zrobić, to połączyć kilka danych wyjściowych w jedną potok, to najprostszą metodą jest użycie:

{ or ( command ) list ; } | tee -a ea.sy >>pea.sy

Curlies spróbują uruchomić zawartość w bieżącej powłoce, podczas gdy parens automatycznie się wyłączy. Mimo to, każdy może ci to powiedzieć i, przynajmniej moim zdaniem,. Rozwiązanie heredoc jest znacznie bardziej wartościową informacją, szczególnie jeśli chcesz zrozumieć, jak naprawdę działa powłoka.

Baw się dobrze!


3

Znalazłem tę odpowiedź, gdy chcę zmodyfikować skrypt instalacyjny, aby napisać dziennik instalacji.

Mój skrypt jest już pełen instrukcji echa, takich jak:

echo "Found OLD run script $oldrunscriptname"
echo "Please run OLD tmunsetup script first!"

Nie chciałem, aby instrukcja tee go uruchomiła (lub inny skrypt wywołujący istniejącą z tee), więc napisałem:

#!/bin/bash
# A Shell subroutine to echo to screen and a log file

LOGFILE="junklog"

echolog()
(
echo $1
echo $1 >> $LOGFILE
)


echo "Going"
echolog "tojunk"

# eof

Więc teraz w moim oryginalnym skrypcie mogę po prostu zmienić „echo” na „echolog”, gdzie chcę dane wyjściowe w pliku dziennika.

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.