Должен ли я использовать одинарные или двойные угловые скобки для перенаправления в / dev / null?

18

Большинство ответов здесь [ 1 ] [ 2 ] [ 3 ] используют одну угловую скобку для перенаправления в / dev / null, например так:

command > /dev/null

Но добавление в / dev / null тоже работает:

command >> /dev/null

За исключением лишнего символа, есть ли причина не делать этого? Является ли какой-либо из них "более приятным" для базовой реализации / dev / null?

Edit: открыто (2) страница руководство говорит lseek вызывается перед каждой записью в файл в режиме добавления:

O_APPEND
Файл открывается в режиме добавления. Перед каждой записью (2) смещение файла помещается в конец файла, как будто с lseek (2). Модификация смещения файла и операция записи выполняются как один атомарный шаг.

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

O_TRUNC
Если файл уже существует и является обычным файлом, и режим доступа позволяет записывать (т. Е. O_RDWR или O_WRONLY), он будет усечен до длины 0. Если файл является файлом FIFO или терминальным устройством, флаг O_TRUNC игнорируется. В противном случае эффект O_TRUNC не определен.

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

Итак, действительно ли усечение / dev / null не определено? И влияют ли вызовы lseek на производительность записи?

Морган
источник

Ответы:

27

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

Таким образом, в конце концов, это просто короче, чтобы написать > /dev/nullс одним >знаком.

Что касается отредактированного дополнения:

Страница man open (2) сообщает, что lseek вызывается перед каждой записью в файл в режиме добавления.

Если вы внимательно прочитаете, вы увидите, что он говорит (выделение мое):

смещение файла располагается в конце файла, как если бы это было с помощью lseek (2)

Это означает, что он (не должен) фактически вызывать lseekсистемный вызов, и эффект также не является строго одинаковым: вызов lseek(fd, SEEK_END, 0); write(fd, buf, size);без O_APPENDне такой же, как запись в режиме добавления, поскольку при отдельных вызовах другой процесс может записывать в файл между системными вызовами, уничтожающий добавленные данные. В режиме добавления этого не происходит (за исключением NFS, которая не поддерживает режим реального добавления ).

Текст в стандарте не упоминается lseekв этой точке, только что запись будет идти до конца файла.

Итак, действительно ли усечение / dev / null не определено?

Судя по отрывку из Священного Писания, очевидно, он определяется реализацией. Это означает, что любая вменяемая реализация будет делать то же самое, что и с pipe и TTY, а именно, ничего. Безумная реализация может сделать что-то еще, и, возможно, усечение может означать что-то разумное в случае какого-либо другого файла устройства.

И влияют ли вызовы lseek на производительность записи?

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

ilkkachu
источник
-3

Если это эффективность, которую вы хотите, используйте command >&-вместо этого. Это закрывает дескриптор файла, а не перенаправляет его, поэтому не тратится время на написание чего-либо.

db48x
источник
3
Не закрывайте потоки меньше 3. Это совмещает дескрипторы std * со случайными дескрипторами файлов; потенциально с катастрофическими результатами.
Джошуа
7
Если вы просто закроете дескриптор файла, программа будет получать ошибки при каждом вызове записи, что, вероятно, приведет к раздражающим сообщениям об ошибках и, возможно, завершению программы перед завершением ее задачи.
ilkkachu