pomija komunikaty stderr w skrypcie bash

48

Rozważ następującą (nieco głupią) nazwę skryptu „test1.sh”:

#/bin/bash
#
sleep 10 &
echo sleep pid = $!
pkill sleep

Kiedy go uruchamiam, otrzymuję nie tylko wynik echa, ale także raport bash o śmierci snu na stderr:

$ ./test1.sh
sleep pid = 3551
./test1.sh: line 5:  3551 Terminated              sleep 10

W takim przypadku chciałbym pominąć wydruk na stderr. Wiem, że mogę to zrobić w wierszu polecenia, jak w:

$ ./test1.sh 2> /dev/null

... ale czy jest jakiś sposób, aby ukryć to w skrypcie? (Wiem, że mogę owinąć go w drugi skrypt i przekierować opakowanie, ale musi być coś łatwiejszego ...)

nieustraszony głupiec
źródło
próbowałeś dodać przekierowanie 2> / dev / null po uśpieniu pkill?
rahul
@rahul: tak, zrobiłem - pkill nie generuje wiadomości, bash jest.
nieustraszony_fool
Użyłem kill zamiast pkill i nie otrzymuję stderr. dziwne ..
rahul
@rahul: czy może to być coś wbudowanego czy niewbudowanego? Czy próbowałeś tego również z pkill?
nieustraszony_fool
tak, wierzę, że tak. Ten sam błąd pojawia się w przypadku pkill, ale nie w przypadku zabicia. Podczas używania kill użyłem pid zamiast nazwy proc.
rahul

Odpowiedzi:

72

Masz rację; pkill nie generuje wiadomości, bash jest. Sugerujesz to

$ ./test1.sh 2> /dev/null

jest możliwym rozwiązaniem. Jak wskazuje UVV, równoważne działanie z poziomu skryptu to

exec 2> /dev/null

Spowoduje to przekierowanie stderr skryptu do /dev/null tej instrukcji, dopóki nie zostanie zmieniona z powrotem. Niezdarne sposoby na przywrócenie tego obejmują

exec 2> /dev/tty

który przekierowuje stderr do terminala. Prawdopodobnie jest to (ale niekoniecznie) pierwotna wersja.

Lub

exec 2>&1

która ustawia stderr na to samo co stdout i prawdopodobnie się myli.

Bardziej niezawodnym sposobem jest

exec 3> i 2
exec 2> / dev / null
(rób rzeczy, w których nie chcesz zobaczyć stderr.) 
exec 2> i 3

który zapisuje oryginalny stderr w deskryptorze pliku 3, a później go przywraca.

Inne sposoby tłumienia samego ogłoszenia procesu śmierci obejmują

(sleep 10 & pkill sleep) 2> /dev/null

i

{ sleep 10 & pkill sleep;} 2> /dev/null

które zmieniają stderr tylko dla zgrupowanych poleceń.

Scott
źródło
To świetna, szczegółowa odpowiedź. Dziękuję Panu!
Keenan Lawrence
Czy są jakieś niebezpieczeństwa związane z zapisywaniem stdini tworzeniem stderrnowych deskryptorów plików, wysyłaniem oryginalnych deskryptorów /dev/nulli przywracaniem ich?
Alexej Magura
Cóż, przypuszczam, że jeśli uruchomisz program, który (bez twojej wiedzy) napisał do deskryptora pliku 3 (lub 4), operacja ta zakończy się niepowodzeniem w normalnych okolicznościach. Ale program można napisać, aby zignorować awarię i kontynuować bez zgłaszania; wtedy nigdy byś nie wiedział. Ale jeśli deskryptor pliku 1 (lub 2) został „zaparkowany” na deskryptorze pliku 3 (lub 4), wówczas program ten nagle zapisałby na standardowe wyjście lub stderr skryptu. Ale to bardzo wymyślny przykład i wciąż minimalne niebezpieczeństwo. Czy miałeś coś na myśli?
Scott
1
FWIW, faworyzuję pogrupowane podejście Scotta, tj.{ sleep 10 & pkill sleep;} 2> /dev/null
nieustraszony_dz
9

Zgodnie z tym możesz zrobić coś takiego:

#!/bin/bash
exec 2>/dev/null
ls -al test
UVV
źródło