Podejrzewam, dlaczego ma to wiele wspólnego z wizją / projektowaniem, które ukształtowało Uniksa (a co za tym idzie Linuksa) oraz wynikające z niego korzyści.
Nie ma wątpliwości, że nie ma dodatkowej korzyści w zakresie wydajności, jeśli nie rozpędza się dodatkowego procesu, ale myślę, że jest coś więcej: wczesny Unix miał metaforę „wszystko jest plikiem”, co ma nieoczywistą, ale elegancką zaletę, jeśli spojrzysz na z perspektywy systemowej, a nie z perspektywy skryptów powłoki.
Załóżmy, że masz null
program wiersza polecenia i /dev/null
węzeł urządzenia. Z punktu widzenia skryptowania powłoki foo | null
program jest naprawdę przydatny i wygodny , a foo >/dev/null
pisanie zajmuje trochę więcej czasu i może wydawać się dziwny.
Ale oto dwa ćwiczenia:
Spójrzmy prawdzie w realizacji programu null
przy użyciu istniejących narzędzi Unix i /dev/null
- łatwa: cat >/dev/null
. Gotowy.
Czy możesz wdrożyć /dev/null
pod względem null
?
Masz całkowitą rację, że kod C, aby po prostu odrzucić dane wejściowe, jest trywialny, więc może nie być jeszcze oczywiste, dlaczego warto mieć plik wirtualny dostępny dla zadania.
Zastanów się: prawie każdy język programowania musi już pracować z plikami, deskryptorami plików i ścieżkami plików, ponieważ były one od początku częścią uniksowego paradygmatu „wszystko jest plikiem”.
Jeśli wszystko, co masz, to programy, które piszą na standardowe wyjście, cóż, program nie dba o to, czy przekierujesz je do wirtualnego pliku, który połyka wszystkie zapisy, lub potoku do programu, który połyka wszystkie zapisy.
Teraz, jeśli masz programy, które pobierają ścieżki plików zarówno do odczytu, jak i zapisu danych (co robi większość programów) - i chcesz dodać do tych programów funkcję „pustego wejścia” lub „odrzuć to wyjście” - cóż, /dev/null
jest to bezpłatne.
Zauważ, że jego elegancją jest to, że zmniejsza złożoność kodu wszystkich zaangażowanych programów - dla każdego wspólnego, ale specjalnego przypadku użycia, który twój system może zapewnić jako „plik” z rzeczywistą „nazwą pliku”, twój kod może uniknąć dodania niestandardowego polecenia -line opcje i niestandardowe ścieżki kodu do obsługi.
Dobra inżynieria oprogramowania często zależy od znalezienia dobrych lub „naturalnych” metafor dla wyodrębnienia jakiegoś elementu problemu w sposób, który staje się łatwiejszy do myślenia, ale pozostaje elastyczny , dzięki czemu można rozwiązać zasadniczo ten sam zakres problemów wyższego poziomu bez konieczności spędzaj czas i energię psychiczną na ciągłym wdrażaniu rozwiązań tych samych problemów niższego poziomu.
„Wszystko jest plikiem” wydaje się być jednym z takich metaforą dostępu do zasobów: Dzwonisz open
z danej ścieżki w obszarze nazw heirarchical, coraz odniesienia (deskryptor) do obiektu, a można read
i write
itp na deskryptorów plików. Twoje stdin / stdout / stderr to także deskryptory plików, które właśnie zostały dla Ciebie wstępnie otwarte. Twoje potoki to tylko pliki i deskryptory plików, a przekierowanie plików pozwala skleić wszystkie te elementy razem.
Uniksowi udało się tak samo, jak częściowo, ze względu na to, jak dobrze te abstrakcje działały razem, i /dev/null
najlepiej jest to rozumieć jako część tej całości.
PS Warto spojrzeć na uniksową wersję „wszystko jest plikiem” i rzeczy takie /dev/null
jak pierwsze kroki w kierunku bardziej elastycznego i potężnego uogólnienia metafory zaimplementowanej w wielu późniejszych systemach.
Na przykład w Uniksie specjalne obiekty podobne /dev/null
do plików, takie jak musiały zostać zaimplementowane w samym jądrze, ale okazuje się, że wystarczające jest udostępnienie funkcjonalności w postaci pliku / folderu, która od tego czasu stworzyła wiele systemów, które zapewniają sposób dla programów aby to zrobić.
Jednym z pierwszych był system operacyjny Plan 9, stworzony przez tych samych ludzi, którzy stworzyli Uniksa. Później GNU Hurd zrobił coś podobnego ze swoimi „tłumaczami”. Tymczasem Linux skończył się FUSE (który również rozprzestrzenił się na inne systemy głównego nurtu).
cat foo | bar
jest znacznie gorzej (w skali) niżbar <foo
.cat
jest trywialnym programem, ale nawet trywialny program generuje koszty (niektóre z nich są specyficzne dla semantyki FIFO - ponieważ programy nieseek()
mogą znajdować się w FIFO, na przykład program, który można efektywnie zaimplementować za pomocą wyszukiwania, może w końcu wykonać znacznie droższe operacje po otrzymaniu potoku; przy użyciu takiego urządzenia znakowego/dev/null
może sfałszować te operacje lub za pomocą prawdziwego pliku może je zaimplementować, ale FIFO nie zezwala na jakąkolwiek obsługę kontekstową).