echo wysyłane do stderr


1113

Czy istnieje standardowe narzędzie Bash, które działa jak echo, ale wysyła sygnał do stderr zamiast stdout?

Wiem, że mogę to zrobić, echo foo 1>&2ale jest to trochę brzydkie i, jak podejrzewam, podatne na błędy (np. Bardziej prawdopodobne, że zostaną źle zmienione, gdy coś się zmieni).


Odpowiedzi:


1450

Możesz to zrobić, co ułatwia czytanie:

>&2 echo "error"

>&2kopiuje deskryptor pliku # 2 do deskryptora pliku # 1. Dlatego po wykonaniu tego przekierowania oba deskryptory plików będą odnosić się do tego samego pliku: pierwotnie odnosiło się do deskryptora jednego pliku # 2 . Więcej informacji można znaleźć w samouczku ilustrowanym przekierowaniu hakerów Bash .


2
Dowiedziałem się tej sztuczki już jakiś czas temu. Ta strona zawiera kilka dobrych informacji. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio

46
@BCS Nie wiem, jak używać aliasskryptu powłoki. Byłoby to prawdopodobnie bezpieczniejsze w użyciuerrcho(){ >&2 echo $@; }
Braden Best

3
> & 2 jest zwykle umieszczane na końcu. To zadziała, ale jest rzadziej używane
Iskren Ivov Chernev

159
Przez prawie 40 lat, kiedy korzystam z systemów uniksowych, nigdy nie przyszło mi do głowy, że możesz umieścić przekierowanie gdziekolwiek, ale na końcu. Umieszczenie go z przodu w ten sposób czyni go bardziej oczywistym (lub „ułatwia czytanie”, jak mówi @MarcoAurelio). +1 za nauczenie mnie czegoś nowego.
Hefajstos

FYI: jeśli chcesz sformatować lub zrobić coś innego niż po prostu powtórzyć ciąg znaków, musisz przenieść przekierowanie z powrotem na koniec. Na przykład errcho(){ >&2 echo $@|pr -To5;}nie będzie działać. Aby zrobić coś takiego, musisz umieścić przekierowanie gdzieś po ostatniej rurze, na przykład:errcho(){ echo $@|>&2 pr -To5;}
Jon Red

423

Możesz zdefiniować funkcję:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Byłoby to szybsze niż skrypt i nie miałyby żadnych zależności.

Sugestia specyficzna dla bash Camilo Martina używa „tutaj ciągu” i wypisze wszystko, co do niej przekażesz, w tym argumenty (-n), które echo normalnie przełknie:

echoerr() { cat <<< "$@" 1>&2; }

Rozwiązanie Glenna Jackmana pozwala również uniknąć problemu z połykaniem argumentów:

echoerr() { printf "%s\n" "$*" >&2; }

7
Muszę powiedzieć, że echo jest trochę niewiarygodne. echoerr -ne xtnie wypisze „-ne xt”. Lepsze wykorzystanie printfdo tego.
Camilo Martin

10
Och, możesz też użyć kota:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin

2
Nie byłam tego świadoma. Dodany.
James Roth,

4
Lubprintf "%s\n" "$*" >&2
glenn jackman

4
@GKFX Oczywiście działa poprawnie tylko podczas cytowania. Dlaczego ludzie nie cytują swoich sznurków, są poza mną. (gdy nie cytujesz, wszystko oddzielone jedną lub większą liczbą $IFSbiałych znaków jest wysyłane jako osobny argument, co w przypadku echooznacza połączenie ich z literą 0x20s, ale niebezpieczeństwa związane z niedocenianiem wygody o 2 mniej znaków do pisania) .
Camilo Martin

252

Ponieważ 1jest to standardowe wyjście, nie musisz jawnie nadawać mu nazwy przed przekierowaniem wyjścia, >ale możesz po prostu wpisać:

echo Ta wiadomość trafia do stderr> i 2

Ponieważ wydajesz się martwić, że 1>&2trudno będzie Ci rzetelnie pisać, eliminacja zbędnych 1może być dla ciebie niewielką zachętą!


59

Inna opcja

echo foo >>/dev/stderr

4
Czy ta opcja jest przenośna? Czy ktoś wie, czy to nie działa na jakiś uniksowy smak?
Dacav

7
Nie działa w niektórych chrootach, które nie mają dostępu do / dev / stderr.
Zachary Vance

12
Jeśli skrypt, który wykonuje tę linię - nazwijmy ją foo- ma przekierowane własne stderr - np. foo >foo.log 2>&1- wówczas echo foo >/dev/stderrzablokuje wszystkie dane wyjściowe przed nią. >>zamiast tego należy użyć:echo foo >>/dev/stderr
doshea

Podobnie masz /dev/fd/2.
jbruni

@Dacav to na pewno przenośny: /proc/self/fd/2. Zobacz moją odpowiedź poniżej :)
Sebastian,

31

Nie, to standardowy sposób na zrobienie tego. Nie powinno to powodować błędów.


9
Nie powinno to powodować błędów, ale być może bardziej prawdopodobne. OTOH, to nie jest wielka sprawa.
BCS,

6
@ Mike DeSimone: Jeśli ktoś zadziera z kodem, przetasuje dane wyjściowe i nie zna basha, może łatwo upuścić (lub pomylić) plik 1>&2. Wszyscy chcielibyśmy, żeby tak się nie stało, ale jestem pewien, że wszyscy byliśmy miejscami, w których tak się dzieje.
Cascabel,

2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logUps.
BCS,

29
IMHO, jeśli ktoś zadziała z kodem i nie zna basha, może to być najmniejszy z twoich problemów.
Mike DeSimone

7
Myślę, że jeśli to może być problem, powinieneś zacząć używać innego języka: próba uczynienia bash niezawodnym jest przedsięwzięciem głupim.
intuicyjnie

17

Jeśli nie masz nic przeciwko rejestrowaniu wiadomości również w syslog, nie not_so_ugly sposób to:

logger -s $msg

Opcja -s oznacza: „Wyświetlaj komunikat o błędzie standardowym, a także w dzienniku systemowym”.


1
to jest świetne! jak to jest przenośne?
code_monk

@code_monk: Oczekuje się, że polecenie Rejestrator być IEEE Std 1003.2 ( „POSIX.2”) zgodne, Komenda rejestrator jest częścią pakietu util-linux i jest dostępny z Linux Kernel archiwum ⟨ kernel.org/pub/linux/utils / util- linux⟩.
miku

12

Jest to prosta funkcja STDERR, która przekierowuje wejście potoku do STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err

2
Myślę, że możesz zrobić to samo z aliasem i być bardziej zwartym
BCS

lub możesz przesłać bezpośrednio do pliku urządzenia echo what | /dev/stderr...
nowy

11

Uwaga: odpowiadam na pytanie, a nie na mylące / niejasne echo „wyjściowe do stderr” (na które już odpowiedział OP).

Użyj funkcji, aby pokazać zamiar i źródło pożądanej implementacji. Na przykład

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

I error_handlingbędąc:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Powody, które uwzględniają obawy w PO:

  • najładniejsza możliwa składnia (znaczące słowa zamiast brzydkich symboli)
  • trudniej popełnić błąd (szczególnie jeśli ponownie użyjesz skryptu)
  • nie jest to standardowe narzędzie Bash, ale może być standardową biblioteką powłoki dla Ciebie lub Twojej firmy / organizacji

Inne powody:

  • jasność - pokazuje zamiar innym opiekunom
  • prędkość - funkcje są szybsze niż skrypty powłoki
  • wielokrotnego użytku - funkcja może wywoływać inną funkcję
  • konfigurowalność - nie trzeba edytować oryginalnego skryptu
  • debugowanie - łatwiej znaleźć linię odpowiedzialną za błąd (szczególnie jeśli jesteś martwy z mnóstwem wyników przekierowywania / filtrowania)
  • solidność - jeśli brakuje funkcji i nie możesz edytować skryptu, możesz wrócić do korzystania z zewnętrznego narzędzia o tej samej nazwie (np. log_error może być aliasowany do loggera w systemie Linux)
  • przełączanie implementacji - możesz przełączyć się na narzędzia zewnętrzne, usuwając atrybut „x” biblioteki
  • wyjście agnostyczne - nie musisz się już przejmować, czy przejdzie do STDERR czy gdzie indziej
  • personalizacja - możesz skonfigurować zachowanie za pomocą zmiennych środowiskowych

10

Moja sugestia:

echo "my errz" >> /proc/self/fd/2

lub

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2będzie skutecznie wyjście do stderrponieważ /proc/selfjest link do bieżącego procesu, a /proc/self/fdtrzyma procesu otwarte deskryptory plików, a następnie 0, 1i 2stanąć na stdin, stdouti stderrodpowiednio.

/proc/selfLink nie działa na MacOS, jednak /proc/self/fd/*jest dostępny na Termux na Androidzie, ale nie /dev/stderr. Jak wykryć system operacyjny ze skryptu Bash? może pomóc, jeśli chcesz uczynić skrypt bardziej przenośnym, określając, którego wariantu użyć.


5
/proc/selfLink nie działa na MacOS, więc będę trzymać się bardziej prosta /dev/stderrmetoda. Ponadto, jak zauważono w innych odpowiedziach / komentarzach, prawdopodobnie lepiej jest użyć >>do dołączenia.
MarkHu,

4
/proc/self/fd/*jest dostępny w Termux na Androida, ale nie /dev/stderr.
go2null

9

Nie używaj, catponieważ niektóre są tutaj wymienione. catto program, podczas echoi printfsą atakujących (Shell) builtins. Uruchomienie programu lub innego skryptu (również wspomnianego powyżej) oznacza utworzenie nowego procesu ze wszystkimi jego kosztami. Korzystanie z wbudowanych funkcji pisania jest dość tanie, ponieważ nie ma potrzeby tworzenia (wykonywania) procesu (środowiska).

Opner pyta „czy jest jakieś standardowe narzędzie do wyprowadzania ( rury ) do stderr”, odpowiedź Schorta brzmi: NIE… dlaczego? ... przeprojektowane potoki to elementarna koncepcja w systemach takich jak unix (Linux ...) i bash (sh) bazuje na tych koncepcjach.

Zgadzam się z otwieraczem, że przekierowywanie za pomocą takich notacji: &2>1nie jest zbyt przyjemne dla współczesnych programistów, ale to bzdura. Bash nie był przeznaczony do pisania dużych i solidnych programów, ma na celu pomóc administratorom w pracy przy mniejszej liczbie naciśnięć klawiszy ;-)

Przynajmniej możesz umieścić przekierowanie w dowolnym miejscu linii:

$ echo This message >&2 goes to stderr 
This message goes to stderr

1
Mówienie programistom, aby nie korzystali z programów tylko ze względu na wydajność, jest przedwczesną optymalizacją. Eleganckie, łatwe do naśladowania podejście powinno być lepsze niż trudny do zrozumienia kod, który działa lepiej (rzędu milisekund).
GuyPaddock,

@GuyPaddock przepraszam, nie przeczytałeś tego poprawnie. Jodły; Chodzi o przekierowywanie rur, które jest dobrze obsługiwane przez bash. Jeśli ktoś nie lubi (brzydkiej) składni, w jaki sposób przekierowuje bash, powinien przestać implementować skrypty bash lub nauczyć się bash. Druga; powinieneś wiedzieć, jak drogo jest uruchomić nową zaletę w porównaniu z wbudowanym wywoływaniem bash.
return42

1
Istnieje różnica między powiadomieniem kogoś o kompromisach wydajnościowych wbudowanych Bash cata poleceniem komuś, żeby nie używał kota, ponieważ jest wolny. Istnieją niezliczone przypadki użycia, w których kot jest właściwym wyborem, dlatego sprzeciwiam się twojej odpowiedzi.
GuyPaddock,

@GuyPaddock Otwieracz poprosił o echowymianę. Nawet jeśli użyje cat, musi użyć przekierowania bash. tak czy siak. Dlatego nie ma absolutnie żadnego sensu, aby cattutaj korzystać . BTW Używam cat100 razy dziennie, ale nigdy w kontekście, o który prosi otwieracz ... rozumiesz?
return42

8

Inną opcją, na którą ostatnio natknąłem jest:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Wykorzystuje tylko wbudowane Bash, jednocześnie zmniejszając ryzyko wystąpienia błędów wieloliniowych (ponieważ nie trzeba pamiętać o dodawaniu &>2do każdej linii).


1
Nie mogę w to uwierzyć, głosujesz na mnie, gdy zalecam użycie przekierowania bash, a we własnej odpowiedzi używasz przekierowania bash.
return42

1
@ return42 Głosowałem za odrzuceniem twojej odpowiedzi, ponieważ wszystko, co zrobiłem, to powiedział PO, że nie ma lepszej odpowiedzi niż to, od czego zaczęli. To nie jest tak naprawdę odpowiedź. Nie widzę też sugestii podpowłoki w twojej odpowiedzi ... twoja odpowiedź naprawdę po prostu odradza OP nie używać catani żadnego innego narzędzia, co jest nie na temat pytania.
GuyPaddock


6

read to wbudowane polecenie powłoki, które drukuje na stderr i może być używane jak echo bez wykonywania sztuczek przekierowania:

read -t 0.1 -p "This will be sent to stderr"

-t 0.1Jest limit czasu, który wyłącza czytać Głównego funkcjonalność przechowywania jeden wiersz standardowego wejścia do zmiennej.


5
Bash na OS X nie pozwala na „0.1”
James Roth,

2

Stwórz skrypt

#!/bin/sh
echo $* 1>&2

to byłoby twoje narzędzie.

Lub utwórz funkcję, jeśli nie chcesz mieć skryptu w osobnym pliku.


6
Lepiej, żeby była to funkcja (jak odpowiedź Jamesa Rotha) i lepiej przekazać wszystkie argumenty, nie tylko pierwsze.
Cascabel

2
Dlaczego funkcja byłaby lepsza? (Lub alternatywnie: „Lepiej wyjaśnić, dlaczego byłoby lepiej ...”)
Ogre Psalm33,

3
@ OgrePsalm33 Jednym z powodów, dla których funkcja byłaby lepsza, jest to, że podczas wywoływania skryptu zwykle tworzona jest nowa instancja powłoki, która zapewnia środowisko do wykonywania skryptu. Z drugiej strony funkcja jest umieszczana w aktualnie działającym środowisku powłoki. Wywołanie funkcji w tym przypadku byłoby znacznie bardziej wydajną operacją, ponieważ uniknięto by utworzenia kolejnego wystąpienia powłoki.
destenson

-10

Mac OS X: Wypróbowałem zaakceptowaną odpowiedź i kilka innych odpowiedzi, a wszystkie z nich spowodowały napisanie STDOUT, a nie STDERR na moim komputerze Mac.

Oto przenośny sposób zapisu standardowego błędu za pomocą Perla:

echo WARNING! | perl -ne 'print STDERR'

lol zanotuj wszystko, czego chcesz, ale to jest rozwiązanie, którego faktycznie używam w moim kodzie!
Noah Sussman
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.