> & - более эффективен, чем> / dev / null?


58

Вчера я прочитал этот комментарий, который говорит, что в оболочке (по крайней мере bash) >&-"имеет тот же результат, что и" >/dev/null.

Этот комментарий фактически ссылается на руководство АБС как на источник информации. Но этот источник говорит, что >&-синтаксис «закрывает файловые дескрипторы».

Мне не ясно, являются ли два действия закрытия файлового дескриптора и перенаправления его на нулевое устройство полностью эквивалентными. Итак, мой вопрос: они?

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

Другими словами, я всегда задавался вопросом, >/dev/nullозначает ли это средство, cat mybigfile >/dev/nullкоторое фактически обрабатывает каждый байт файла и записывает его в тот, /dev/nullкоторый его забывает. С другой стороны, если оболочка встречает закрытый файловый дескриптор, я склонен думать (но не уверен), что она просто ничего не будет писать, хотя остается вопрос, catбудет ли по- прежнему считываться каждый байт.

Этот комментарий говорит >&-и >/dev/null« должен » быть таким же, но это не настолько громкий ответ для меня. Я хотел бы получить более авторитетный ответ со ссылкой на стандарт или ядро ​​источника или нет ...


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

Ответы:


71

Нет, вы определенно не хотите закрывать файловые дескрипторы 0, 1 и 2.

Если вы сделаете это, то в первый раз, когда приложение откроет файл, оно станет stdin / stdout / stderr ...

Например, если вы делаете:

echo text | tee file >&-

Когда tee(по крайней мере, некоторые реализации, такие как busybox ') откроет файл для записи, он будет открыт в файловом дескрипторе 1 (stdout). Так teeнапишу textдважды в file:

$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193)                 = 5
write(1, "text\n", 5)                   = 5
write(1, "text\n", 5)                   = 5
read(0, "", 8193)                       = 0
exit_group(0)                           = ?

Известно, что это вызывает уязвимости в безопасности. Например:

chsh 2>&-

И chsh(приложение setuid) может в конечном итоге писать сообщения об ошибках в /etc/passwd.

Некоторые инструменты и даже некоторые библиотеки пытаются защититься от этого. Например, GNU teeпереместит файловый дескриптор на один выше 2, если файлы, которые он открывает для записи, назначены 0, 1, 2, а busybox teeнет.

Большинство инструментов, если они не могут записать в stdout (потому что, например, он не открыт), сообщат об ошибке на stderr (на языке пользователя, что означает дополнительную обработку для открытия и анализа файлов локализации ...), поэтому это будет значительно менее эффективно и, возможно, приведет к сбою программы.

В любом случае, это не будет более эффективным. Программа по-прежнему будет выполнять write()системный вызов. Это может быть более эффективным, только если программа прекращает запись в stdout / stderr после первого сбоя write()системного вызова, но программы обычно этого не делают. Обычно они либо выходят с ошибкой, либо продолжают попытки.


4
Я думаю, что этот ответ был бы еще лучше, если бы последний абзац был в самом верху (поскольку именно это наиболее точно отвечает на вопрос ОП), а затем продолжалось обсуждение, почему это плохая идея, даже если он в основном работал. Но я возьму это, воздержусь. ;)
CVn

@ StéphaneChazelas: Как сказал Майкл, я бы ожидал, что последний параграф будет на вершине, но спасибо за разъяснение, что на самом деле, вероятно, только создает проблемы. Таким образом, я думаю, что вспомогательный вопрос будет, когда закрытие FD будет действительно полезным? Или я должен задать это как отдельный вопрос?
Джамадагни

@jamadagni, см. некоторые примеры , см. unix.stackexchange.com/search?q=user%3A22565+%223%3E%26-%22
Стефан Шазелас

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

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

14

Я всегда задавался вопросом, >/dev/nullозначает ли это, cat mybigfile >/dev/nullчто фактически обрабатывает каждый байт файла и записывает его, /dev/nullкоторый его забывает.

Это не полный ответ на ваш вопрос, но да, выше, как это работает.

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само по себе не касается.


2
Чтобы расширить ваш ответ: Да, cat mybigfile > /dev/nullприведет catк чтению каждого байта bigfileв памяти. И для каждого nбайта он будет вызывать write(1, buffer, n). Без ведома catпрограммы, writeони ничего не сделают (за исключением, может быть, некоторой тривиальной бухгалтерии). Запись в /dev/nullне требует обработки каждого байта.
G-Man говорит: «Восстанови Монику»

2
Я помню, что был потрясен, когда прочитал исходный код ядра Linux для устройства / dev / null. Я ожидал, что будет какая-то тщательно продуманная система свободных () буферов и т. Д., Но, нет, это просто возврат ().
Брайан Минтон

4
@ G-Man: я не знаю, что вы можете гарантировать, что это будет правдой во всех случаях. Сейчас я не могу найти доказательства, но я вспоминаю некоторую реализацию того catили другого cp, которая работала бы, mmapвставляя большие куски исходного файла в память, а затем вызывая write()сопоставленную область. Если бы вы писали /dev/null, write()вызов сразу же возвращался бы без сбоев на страницах исходного файла, поэтому он никогда не будет считан с диска.
Нейт Элдредж,

2
Кроме того, что-то вроде GNU catдействительно работает на многих платформах, но случайный взгляд на исходный код покажет много #ifdefs: это не буквально один и тот же код, который выполняется на всех платформах, и есть много зависимых от системы разделов.
Нейт Элдредж,

@NateEldredge: Интересный момент, но я просто опирался на ответ Майкла, так что вы не столько противоречите мне, сколько противоречите Майклу.
G-Man говорит: «Восстановите Монику»
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.