Почему /dev /null файл? Почему его функция не реализована как простая программа?

Я новичок в понимании концепции специальных файлов в Linux. Однако наличие специального файла в /dev кажется глупым, когда его функция может быть реализована несколькими строками в C, насколько мне известно.

Кроме того, вы можете использовать его примерно таким же образом, то есть подключаться к null вместо перенаправления на /dev/null. Есть ли конкретная причина для его использования в качестве файла? Не делает ли это файл причиной многих других проблем, таких как слишком много программ, обращающихся к одному и тому же файлу?

108 голосов | спросил Ankur S 16 PMpMon, 16 Apr 2018 18:28:04 +030028Monday 2018, 18:28:04

9 ответов


150

В дополнение к преимуществам использования персонального специального устройства основным преимуществом является модульность . /dev /null может использоваться практически в любом контексте, где ожидается файл, а не только в конвейерах оболочки. Рассмотрим программы, которые принимают файлы в качестве параметров командной строки.

 # We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

Это все случаи, когда использование программы в качестве источника или приемника было бы чрезвычайно громоздким. Даже в случае оболочки оболочки, stdout и stderr могут быть перенаправлены на файлы независимо друг от друга, что трудно сделать с исполняемыми файлами в качестве приемников:

 # Suppress errors, but print output.
$ grep foo * 2>/dev/null
ответил ioctl 16 PMpMon, 16 Apr 2018 23:55:58 +030055Monday 2018, 23:55:58
62

Справедливости ради, он не является обычным файлом per se; это специальное устройство символов :

$ file /dev/null
/dev/null: character special (3/2)

Он функционирует как устройство, а не как файл или программа, означает, что это более простая операция для перенаправления ввода или вывода из него, поскольку она может быть присоединена к любому файловому дескриптору, включая стандартный ввод /вывод /ошибку.

ответил DopeGhoti 16 PMpMon, 16 Apr 2018 18:56:28 +030056Monday 2018, 18:56:28
54

Я подозреваю, что почему имеет много общего с видением /дизайном, который сформировал Unix (и, следовательно, Linux), и преимущества, вытекающие из него.

Несомненно, есть незначительное преимущество в производительности, чтобы не развернуть дополнительный процесс, но я думаю, что есть еще кое-что: ранняя Unix имела метафору «все это файл», которая имеет неочевидное, но элегантное преимущество, если вы смотрите на него с точки зрения системы, а не на сценарии оболочки.

Скажите, что у вас есть программа командной строки null и /dev/null узла устройства. С точки зрения оболочки, foo | null действительно действительно полезный и удобный , а foo >/dev/null занимает немного больше времени для ввода и может показаться странным.

Но вот два упражнения:

  1. Давайте реализуем программу null с помощью существующих инструментов Unix и /dev/null - easy: cat >/dev/null. Готово.

  2. Можете ли вы реализовать /dev/null в терминах null?

Вы абсолютно правы, что код C, который просто отбрасывает ввод, тривиален, поэтому он может быть еще не очевидным. why полезно иметь виртуальный файл для этой задачи.

Рассмотрим: почти каждый язык программирования уже должен работать с файлами, файловыми дескрипторами и файловыми путями, потому что они были частью парадигмы Unix «все это файл» с самого начала.

Если все, что у вас есть, это программы, которые пишут на stdout, ну, программа не заботит, перенаправляете ли вы их в виртуальный файл, который проглатывает все записи, или трубу в программу, которая проглатывает все записи.

Теперь, если у вас есть программы, которые берут пути к файлам для чтения или записи данных (что делает большинство программ) - и вы хотите добавить функциональные возможности «пустой ввод» или «отказаться от этого вывода» для этих программ - ну, с помощью /dev/null, который поставляется бесплатно.

Обратите внимание, что изяществом является то, что это снижает сложность кода для всех задействованных программ - для каждой обычной, но специальной программы, которую ваша система может предоставить как «файл» с фактическим «именем файла», ваш код может избежать добавление пользовательских параметров командной строки и настраиваемых путей кода для обработки.

Хорошая разработка программного обеспечения часто зависит от поиска хороших или «естественных» метафор для абстрагирования некоторого элемента проблемы таким образом, что становится легче думать о , но остается гибким , так что вы можете решить в основном тот же ряд проблем более высокого уровня, не тратя время и умственную энергию на постоянное повторное решение решений для тех же проблем нижнего уровня.

«Все является файлом», похоже, является одной из таких метафору для доступа к ресурсам: вы вызываете open заданного пути в иерархическом пространстве имен, получая ссылку (файловый дескриптор) на объект и вы можете read и write и т. д. в дескрипторах файла. Ваш stdin /stdout /stderr также являются файловыми дескрипторами, которые только что были предварительно открыты для вас. Ваши трубы - это просто файлы и файловые дескрипторы, а перенаправление файлов позволяет склеить все эти части вместе.

Unix преуспел так же сильно, как и частично, из-за того, насколько хорошо эти абстракции работали вместе, а /dev/null лучше всего понимается как часть этого целого.


P.S. Стоит посмотреть на версию Unix «все это файл» и такие вещи, как /dev/null, как первые шаги к более гибкому и мощному обобщению метафоры, которая была реализована во многих системах, которые последовало.

Например, в Unix в самом ядре должны были быть реализованы специальные файловые объекты вроде /dev/null, но оказалось, что он достаточно полезен для раскрытия функциональности в форме файла /папки что с тех пор были созданы несколько систем, которые предоставляют возможность программам делать это.

Одной из первых была операционная система Plan 9, созданная некоторыми изтех же людей, которые сделали Unix. Позже GNU Hurd сделал что-то подобное с его «переводчиками». Между тем, Linux закончил получать FUSE (который также распространился и на другие основные системы).

ответил mtraceur 17 AMpTue, 17 Apr 2018 01:05:18 +030005Tuesday 2018, 01:05:18
15

Я думаю, что /dev/null является символьным устройством (которое ведет себя как обычный файл) вместо программы для причин производительности .

Если это будет программа, это потребует загрузки, запуска, планирования, запуска, а затем остановки и выгрузки программы. Простая программа на C, которую вы описываете, конечно, не будет потреблять много ресурсов, но я думаю, что это имеет существенное значение при рассмотрении большого количества (скажем, миллионов) действий перенаправления /трубопровода, поскольку операции управления процессом являются дорогостоящими в больших масштабах, поскольку они включают контекстные переключатели.

Другое предположение: для передачи в программу требуется память, выделяемая принимающей программой (даже если она будет удалена напрямую после этого). Поэтому, если вы подключаетесь к инструменту, у вас есть потребление двойной памяти, один раз в программе отправки и снова в принимающей программе.

ответил user5626466 16 PMpMon, 16 Apr 2018 19:21:44 +030021Monday 2018, 19:21:44
7

Помимо «все является файлом» и, следовательно, простота использования во всем мире, на котором основаны большинство других ответов, также возникает проблема с производительностью, как упоминает @ user5626466.

Чтобы продемонстрировать на практике, мы создадим простую программу под названием nullread.c:

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

и скомпилировать его с помощью gcc -O2 -Wall -W nullread.c -o nullread

(Примечание: мы не можем использовать lseek (2) на трубах, поэтому только для того, чтобы слить трубку, нужно читать от него, пока он не станет пустым).

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

, тогда как при стандартном перенаправлении файлов /dev/null мы получаем гораздо лучшие скорости (из-за упомянутых фактов: меньше переключения контекста, ядро ​​просто игнорирует данные вместо копирования и т. д.):

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(это должен быть комментарий там, но слишком большой для этого и будет полностью нечитаемым)

ответил Matija Nalis 19 PMpThu, 19 Apr 2018 14:32:10 +030032Thursday 2018, 14:32:10
6

Ваш вопрос задан так, как если бы что-то получилось, возможно, в простоте, используя нулевую программу вместо файла. Возможно, мы можем избавиться от понятия «волшебные файлы» и вместо этого иметь только «обычные трубы».

Но рассмотрим, труба также является файлом . Обычно они не называются и поэтому могут обрабатываться только через их файловые дескрипторы.

Рассмотрим этот несколько надуманный пример:

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

Используя подстановку процессов Bash, мы можем выполнить одно и то же с помощью более обходного пути:

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

Замените grep на echo, и мы можем видеть под обложками:

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

Конструкция <(...) просто заменяется именем файла, и grep считает, что он открывает какой-либо старый файл, он просто называется /dev/fd/63. Здесь /dev/fd - это волшебный каталог, который делает именованные каналы для каждого файлового дескриптора, которым обладает доступ к нему.

Мы могли бы сделать это менее волшебным с помощью mkfifo, чтобы создать именованный канал, который отображается в ls, и все, как обычный файл:

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

В другом месте:

$ echo -e 'foo\nbar\nbaz' > foofifo

и вот, grep выведет foo.

Я думаю, что когда вы понимаете, что трубы и обычные файлы и специальные файлы, такие как /dev /null, - это всего лишь файлы, очевидно, что реализация нулевой программы - это more . Ядро должно обрабатывать записи в файл в любом случае, но в случае /dev /null он может просто удалить записи на полу, тогда как с помощью канала он должен фактически передать байты в другую программу, которая затем должна фактически прочитайте их.

ответил Phil Frost 20 AMpFri, 20 Apr 2018 01:07:47 +030007Friday 2018, 01:07:47
0

Я бы сказал, что проблема безопасности выходит за рамки исторических парадигм и производительности. Ограничение количества программ с привилегированными учетными данными, независимо от того, насколько просто, является основополагающим принципом безопасности системы. Замена /dev/null, безусловно, потребует наличия таких привилегий из-за использования системными службами. Современные рамки безопасности делают отличную работу по предотвращению эксплойтов, но они не являются надежными. Ядро, доступное как файл, гораздо труднее использовать.

ответил NickW 20 PMpFri, 20 Apr 2018 19:13:01 +030013Friday 2018, 19:13:01
0

Как уже указывалось другими, /dev/null - это программа, состоящая из нескольких строк кода. Просто эти строки кода являются частью ядра.

Чтобы сделать его более понятным, вот реализация Linux: устройство символов вызывает функции при чтении или записи. Запись на /dev/null вызывает write_null , при чтении вызовов read_null , зарегистрирован здесь .

Буквально несколько строк кода: эти функции ничего не делают. Вам нужно больше строк кода, чем пальцы на руках, только если вы считаете функции, отличные от чтения и записи.

ответил Matthieu Moy 23 PMpMon, 23 Apr 2018 18:14:08 +030014Monday 2018, 18:14:08
-2

Я надеюсь, что вы также знаете об /dev /chargen /dev /zero и других подобных им, включая /dev /null.

В LINUX /UNIX есть несколько из них - доступный, чтобы люди могли хорошо использовать WELL WRITTEN CODE FrAGMEnTS.

Chargen предназначен для создания определенного и повторяющегося шаблона символов - он довольно быстр и будет ограничивать пределы серийного устройств, и это поможет отлаживать последовательные протоколы, которые были написаны и не прошли какой-либо тест.

Zero предназначен для заполнения существующего файла или вывода большого количества нулей

/dev /null - это еще один инструмент с той же идеей.

Все эти инструменты в вашем наборе инструментов означают, что у вас есть половина шансов сделать существующую программу, сделать что-то уникальное, независимо от их (ваша конкретная потребность) в качестве устройств или замены файлов

Позволяет настроить конкурс, чтобы увидеть, кто может произвести самый захватывающий результат, учитывая только несколько символов в вашей версии LINUX.

ответил helpful 20 PMpFri, 20 Apr 2018 16:45:25 +030045Friday 2018, 16:45:25

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132