Wczoraj przeczytałem ten komentarz SO, który mówi, że w powłoce (przynajmniej bash
) >&-
„ma taki sam wynik jak” >/dev/null
.
Ten komentarz faktycznie odnosi się do przewodnika ABS jako źródła jego informacji. Ale to źródło mówi, że >&-
składnia „zamyka deskryptory plików”.
Nie jest dla mnie jasne, czy dwie akcje zamknięcia deskryptora pliku i przekierowania go do urządzenia zerowego są całkowicie równoważne. Moje pytanie brzmi: czy są?
Na pierwszy rzut oka wydaje się, że zamknięcie deskryptora jest jak zamknięcie drzwi, ale przekierowanie do zerowego urządzenia otwiera drzwi do otchłani! Oba nie wydają mi się dokładnie takie same, ponieważ jeśli zobaczę zamknięte drzwi, nie spróbuję z nich niczego wyrzucić, ale jeśli zobaczę otwarte drzwi, założę się, że mogę.
Innymi słowy, zawsze zastanawiałem się, czy >/dev/null
środki, które cat mybigfile >/dev/null
faktycznie przetwarzają każdy bajt pliku i zapisać go na /dev/null
którym zapomina. Z drugiej strony, jeśli powłoka napotka zamknięty deskryptor pliku, myślę (ale nie jestem pewien), że po prostu nic nie napisze, choć pozostaje pytanie, czy cat
nadal będzie czytał każdy bajt.
Ten komentarz mówi >&-
i >/dev/null
„ powinien ” być taki sam, ale nie jest to dla mnie tak głośna odpowiedź. Chciałbym uzyskać bardziej autorytatywną odpowiedź z pewnym odniesieniem do standardowego lub źródłowego rdzenia, czy nie ...
źródło
Odpowiedzi:
Nie, z pewnością nie chcesz zamykać deskryptorów plików 0, 1 i 2.
Jeśli to zrobisz, aplikacja po raz pierwszy otworzy plik, zmieni się na stdin / stdout / stderr ...
Na przykład, jeśli wykonasz:
Kiedy
tee
(przynajmniej niektóre implementacje, takie jak busybox) otworzy plik do zapisu, zostanie on otwarty w deskryptorze pliku 1 (standardowe wyjście). Więctee
napiszętext
dwa razy wfile
:Wiadomo, że powoduje to luki w zabezpieczeniach. Na przykład:
I
chsh
(aplikacja setuid) może kończyć się pisaniem komunikatów o błędach w/etc/passwd
.Niektóre narzędzia, a nawet niektóre biblioteki starają się temu zapobiec. Na przykład GNU
tee
przeniesie deskryptor pliku na jeden powyżej 2, jeśli pliki, które otwiera do zapisu, mają przypisane 0, 1, 2, a zajętytee
nie.Większość narzędzi, jeśli nie mogą pisać na standardowe wyjście (ponieważ na przykład nie jest otwarte), zgłosi komunikat o błędzie na stderr (w języku użytkownika, co oznacza dodatkowe przetwarzanie do otwierania i analizowania plików lokalizacyjnych ...), więc będzie znacznie mniej wydajny i może spowodować awarię programu.
W każdym razie nie będzie bardziej wydajne. Program nadal wykona
write()
wywołanie systemowe. Może być bardziej efektywny tylko wtedy, gdy program zrezygnuje z zapisu na stdout / stderr po pierwszym nieudanymwrite()
wywołaniu systemowym, ale programy na ogół tego nie robią. Zazwyczaj wychodzą z błędem lub próbują dalej.źródło
To nie jest pełna odpowiedź na twoje pytanie, ale tak, powyższe to, jak to działa.
cat
odczytuje nazwane pliki lub standardowe wejście, jeśli nie ma nazw plików, i wysyła na standardowe wyjście zawartość tych plików, dopóki nie napotka EOF na (łącznie ze standardowym wejściem) na ostatnim nazwanym pliku. To jest jego praca.Dodając
>/dev/null
przekierowujesz standardowe wyjście do / dev / null. Jest to specjalny plik (węzeł urządzenia), który wyrzuca wszystko, co w nim zapisane (i natychmiast zwraca EOF podczas odczytu). Zauważ, że przekierowanie We / Wy jest funkcją zapewnianą przez powłokę, a nie przez poszczególne aplikacje, i że w nazwie / dev / null nie ma nic magicznego , tylko to, co dzieje się tam w większości systemów uniksowych .Należy również zauważyć, że specyficzna mechanika węzłów urządzeń różni się w zależności od systemu operacyjnego, ale cat (co w systemie GNU oznacza coreutils) jest wieloplatformowy (ten sam kod źródłowy musi działać przynajmniej w systemie Linux i Hurd) i dlatego nie może przyjmować zależności od konkretnych jąder systemu operacyjnego. Ponadto nadal działa, jeśli utworzysz alias / dev / null (w systemie Linux oznacza to węzeł urządzenia o tym samym głównym / mniejszym numerze urządzenia) o innej nazwie. I zawsze jest tak w przypadku pisania gdzie indziej, który zachowuje się tak samo (powiedzmy, / dev / zero).
Wynika z tego, że
cat
nie jest świadomy specjalnych właściwości / dev / null i rzeczywiście prawdopodobnie nie jest świadomy przekierowania, ale nadal musi wykonać dokładnie taką samą pracę: odczytuje nazwane pliki i wysyła zawartość plik / te na standardowe wyjście. To, że standardowe wyjściecat
zdarza się popaść w pustkę, nie jest czymścat
związanym z tym.źródło
cat mybigfile > /dev/null
spowodujecat
odczytanie każdego bajtubigfile
pamięci. I dla każdegon
bajtu zadzwoniwrite(1, buffer, n)
. Bez wiedzy ocat
programiewrite
nie zrobi absolutnie nic (może z wyjątkiem trywialnej księgowości). Zapisywanie do/dev/null
nie wymaga przetwarzania każdego bajtu.cat
lubcp
że będzie działać przezmmap
ing duże kawałki pliku źródłowego do pamięci, a następnie wywołaniewrite()
na wyznaczonej regionie. Jeśli piszesz do/dev/null
,write()
wywołanie natychmiast powróci bez błędów na stronach pliku źródłowego, więc nigdy nie zostanie odczytane z dysku.cat
działa na wielu platformach, ale przypadkowe spojrzenie na kod źródłowy pokaże wiele#ifdef
s: to nie jest dosłownie ten sam kod, który działa na wszystkich platformach, i jest wiele sekcji zależnych od systemu.