Я подозреваю, что причина во многом связана с концепцией / дизайном, которые сформировали Unix (и, следовательно, Linux), и вытекающими из этого преимуществами.
Без сомнения, есть немаловажное преимущество в производительности, если не затягивать дополнительный процесс, но я думаю, что это еще не все: в раннем Unix была метафора «все - файл», которая имеет неочевидное, но элегантное преимущество, если вы посмотрите на это с точки зрения системы, а не с точки зрения сценариев оболочки.
Скажем, у вас есть программа null
командной строки и /dev/null
узел устройства. С точки зрения сценариев оболочки, foo | null
программа на самом деле действительно полезна и удобна , foo >/dev/null
набирает текст чуть дольше и может показаться странной.
Но вот два упражнения:
Давайте реализуем программу , null
используя существующие инструменты Unix и /dev/null
- легко: cat >/dev/null
. Готово.
Можете ли вы реализовать /dev/null
с точки зрения null
?
Вы абсолютно правы в том, что код на C, который просто отбрасывает ввод, тривиален, поэтому может быть еще не очевидно, почему полезно иметь виртуальный файл для этой задачи.
Учтите: почти каждый язык программирования уже должен работать с файлами, дескрипторами файлов и путями к файлам, потому что они были частью парадигмы Unix "все является файлом" с самого начала.
Если все, что у вас есть, это программы, которые пишут в stdout, то программе все равно, будете ли вы перенаправлять их в виртуальный файл, который поглощает все записи, или канал в программу, которая поглощает все записи.
Теперь, если у вас есть программы, которые используют пути к файлам для чтения или записи данных (что делает большинство программ) - и вы хотите добавить в эти программы функции «пустой ввод» или «сбросить этот вывод» - ну, /dev/null
это бесплатно.
Обратите внимание, что его элегантность заключается в том, что он уменьшает сложность кода всех участвующих программ - для каждого общего, но особого варианта использования, который ваша система может предоставить в виде «файла» с фактическим «именем файла», ваш код может избежать добавления пользовательских команд -линии и пользовательские пути кода для обработки.
Хорошая разработка программного обеспечения часто зависит от нахождения хороших или «естественных» метафор для абстрагирования некоторого элемента проблемы таким образом, который становится более легким для размышления, но остается гибким , так что вы можете решить в основном тот же диапазон задач более высокого уровня без необходимости тратить время и умственную энергию на постоянное воплощение решений одних и тех же проблем более низкого уровня.
«Все является файлом», по-видимому, является одной из таких метафор для доступа к ресурсам: вы вызываете open
заданный путь в иерархическом пространстве имен, получаете ссылку (дескриптор файла) на объект, и вы можете read
и write
, и т. Д. На дескрипторы файлов. Ваш stdin / stdout / stderr также является файловым дескриптором, который только что был предварительно открыт для вас. Ваши каналы - это просто файлы и файловые дескрипторы, а перенаправление файлов позволяет вам склеивать все эти части вместе.
Unix преуспел так же, как и частично, благодаря тому, как хорошо эти абстракции работали вместе, и /dev/null
его лучше всего понимать как часть этого целого.
PS Стоит взглянуть на версию Unix «все является файлом» и тому подобное, /dev/null
в качестве первых шагов к более гибкому и мощному обобщению метафоры, которое было реализовано во многих последующих системах.
Например, в Unix специальные файловые объекты, подобные тому, которые /dev/null
должны были быть реализованы в самом ядре, но оказывается, что это достаточно полезно для предоставления функциональности в форме файлов / папок, что с тех пор было создано несколько систем, которые обеспечивают способ для программ сделать это.
Одной из первых была операционная система Plan 9, созданная теми же людьми, что и Unix. Позже GNU Hurd сделал нечто подобное со своими «переводчиками». Между тем, Linux в конечном итоге получил FUSE (который теперь распространился и на другие основные системы).
cat foo | bar
гораздо хуже (в масштабе), чемbar <foo
.cat
это тривиальная программа, но даже тривиальная программа создает затраты (некоторые из них специфичны для семантики FIFO - потому что программы не могут бытьseek()
внутри FIFO, например, программа, которая может быть эффективно реализована с помощью поиска, может в итоге выполнять гораздо более дорогие операции когда передается конвейер; с помощью символьного устройства,/dev/null
которое может имитировать эти операции, или с помощью реального файла, он может их реализовывать, но FIFO не допускает какой-либо контекстно-зависимой обработки).