Вчера я прочитал этот комментарий, который говорит, что в оболочке (по крайней мере bash
) >&-
"имеет тот же результат, что и" >/dev/null
.
Этот комментарий фактически ссылается на руководство АБС как на источник информации. Но этот источник говорит, что >&-
синтаксис «закрывает файловые дескрипторы».
Мне не ясно, являются ли два действия закрытия файлового дескриптора и перенаправления его на нулевое устройство полностью эквивалентными. Итак, мой вопрос: они?
На первый взгляд кажется, что закрытие дескриптора похоже на закрытие двери, но перенаправление его на нулевое устройство открывает дверь в подвешенное состояние! Эти две вещи не кажутся мне абсолютно одинаковыми, потому что, если я увижу закрытую дверь, я не буду пытаться выбросить из нее что-либо, но если я увижу открытую дверь, то предположу, что смогу.
Другими словами, я всегда задавался вопросом, >/dev/null
означает ли это средство, cat mybigfile >/dev/null
которое фактически обрабатывает каждый байт файла и записывает его в тот, /dev/null
который его забывает. С другой стороны, если оболочка встречает закрытый файловый дескриптор, я склонен думать (но не уверен), что она просто ничего не будет писать, хотя остается вопрос, cat
будет ли по- прежнему считываться каждый байт.
Этот комментарий говорит >&-
и >/dev/null
« должен » быть таким же, но это не настолько громкий ответ для меня. Я хотел бы получить более авторитетный ответ со ссылкой на стандарт или ядро источника или нет ...
источник
Ответы:
Нет, вы определенно не хотите закрывать файловые дескрипторы 0, 1 и 2.
Если вы сделаете это, то в первый раз, когда приложение откроет файл, оно станет stdin / stdout / stderr ...
Например, если вы делаете:
Когда
tee
(по крайней мере, некоторые реализации, такие как busybox ') откроет файл для записи, он будет открыт в файловом дескрипторе 1 (stdout). Такtee
напишуtext
дважды вfile
:Известно, что это вызывает уязвимости в безопасности. Например:
И
chsh
(приложение setuid) может в конечном итоге писать сообщения об ошибках в/etc/passwd
.Некоторые инструменты и даже некоторые библиотеки пытаются защититься от этого. Например, GNU
tee
переместит файловый дескриптор на один выше 2, если файлы, которые он открывает для записи, назначены 0, 1, 2, а busyboxtee
нет.Большинство инструментов, если они не могут записать в stdout (потому что, например, он не открыт), сообщат об ошибке на stderr (на языке пользователя, что означает дополнительную обработку для открытия и анализа файлов локализации ...), поэтому это будет значительно менее эффективно и, возможно, приведет к сбою программы.
В любом случае, это не будет более эффективным. Программа по-прежнему будет выполнять
write()
системный вызов. Это может быть более эффективным, только если программа прекращает запись в stdout / stderr после первого сбояwrite()
системного вызова, но программы обычно этого не делают. Обычно они либо выходят с ошибкой, либо продолжают попытки.источник
Это не полный ответ на ваш вопрос, но да, выше, как это работает.
cat
читает именованные файлы или стандартный ввод, если файлы не названы, и выводит на свой стандартный вывод их содержимое до тех пор, пока он не встретит EOF на (включая стандартный ввод) последнем названном файле. Это его работа.Добавляя,
>/dev/null
вы перенаправляете стандартный вывод в / dev / null. Это специальный файл (узел устройства), который выбрасывает все, что в нем записано (и сразу возвращает EOF при чтении). Обратите внимание, что перенаправление ввода-вывода - это функция, предоставляемая оболочкой, а не каждым отдельным приложением, и что в имени / dev / null нет ничего волшебного , только то, что происходит в большинстве Unix-подобных систем .Также важно отметить, что конкретная механика узлов устройств варьируется от операционной системы к операционной системе, но cat (что в системе GNU означает coreutils) является кроссплатформенной (один и тот же исходный код должен работать как минимум в Linux и Hurd) и, следовательно, не может принимать зависимости от конкретных ядер операционной системы. Кроме того, он все еще работает, если вы создаете псевдоним / dev / null (в Linux это означает узел устройства с тем же основным / второстепенным номером устройства) с другим именем. И всегда есть случай написания где-нибудь еще, который ведет себя практически одинаково (скажем, / dev / zero).
Из этого следует, что
cat
он не знает о специальных свойствах / dev / null и, скорее всего, в первую очередь не знает о перенаправлении, но ему все равно необходимо выполнить точно такую же работу: он читает именованные файлы и выводит содержимое / те файл (ы) к его стандартному выводу. То, что стандартный выводcat
события попадает в пустоту,cat
само по себе не касается.источник
cat mybigfile > /dev/null
приведетcat
к чтению каждого байтаbigfile
в памяти. И для каждогоn
байта он будет вызыватьwrite(1, buffer, n)
. Без ведомаcat
программы,write
они ничего не сделают (за исключением, может быть, некоторой тривиальной бухгалтерии). Запись в/dev/null
не требует обработки каждого байта.cat
или другогоcp
, которая работала бы,mmap
вставляя большие куски исходного файла в память, а затем вызываяwrite()
сопоставленную область. Если бы вы писали/dev/null
,write()
вызов сразу же возвращался бы без сбоев на страницах исходного файла, поэтому он никогда не будет считан с диска.cat
действительно работает на многих платформах, но случайный взгляд на исходный код покажет много#ifdef
s: это не буквально один и тот же код, который выполняется на всех платформах, и есть много зависимых от системы разделов.