Почему tar выводит содержимое файла, если выходной файл / dev / null?

21

У меня есть каталог с более чем 400 ГиБ данных в нем. Я хотел проверить, что все файлы могут быть прочитаны без ошибок, поэтому я подумал о том, как tarэто сделать /dev/null. Но вместо этого я вижу следующее поведение:

$ time tar cf /dev/null .

real    0m4.387s
user    0m3.462s
sys     0m0.185s
$ time tar cf - . > /dev/null

real    0m3.130s
user    0m3.091s
sys     0m0.035s
$ time tar cf - . | cat > /dev/null
^C

real    10m32.985s
user    0m1.942s
sys     0m33.764s

Третья команда, приведенная выше, была принудительно остановлена Ctrl+ Cпосле достаточно долгого выполнения. Более того, в то время как первые две команды работали, индикатор активности устройства хранения .почти всегда был бездействующим. С третьей командой индикатор постоянно горит, что означает чрезвычайную занятость.

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

Интересно, а почему это так? Это какая-то оптимизация? Если да, то зачем tarвообще делать такую ​​сомнительную оптимизацию для такого особого случая?

Я использую GNU tar 1.26 с glibc 2.27 в Linux 4.14.105 amd64.

Руслан
источник
7
В качестве практической альтернативы рассмотрим что-то подобное find . -type f -exec shasum -a256 -b '{}' +. Мало того, что он фактически читает и проверяет все данные, но если вы сохраняете вывод, вы можете запустить его позже, чтобы убедиться, что содержимое файлов не изменилось.
Ильмари Каронен
Для измерения вещей , которые вы можете использовать pv: tar -cf - | pv >/dev/null. Это обходит проблему и дает вам информацию о прогрессе (различные pvварианты)
xenoid
Вы попали в хорошо известную функцию промаха GNU tar. Используйте, gtar -cf /dev/zero ...чтобы получить то, что вам нравится.
Шили

Ответы:

25

Это является документированной оптимизация :

Когда архив создается для /dev/null, GNU tar пытается минимизировать операции ввода и вывода. Система резервного копирования Amanda, при использовании с GNU tar, имеет начальный этап определения размера, который использует эту функцию.

Мур
источник
4
Ах, это не было описано на странице руководства, которую я установил. Надо было попробовать info tarвместо этого ...
Руслан
9
Они действительно должны синхронизировать страницы man & info, это практически ошибка, которой они не
делают
9
@Ruslan В большинстве утилит GNU страница руководства содержит только краткое резюме, в основном достаточно хорошее, когда вы помните, что у него есть возможность что-то сделать, но не помните его имя. Полная документация представлена ​​в формате, который плохо переводится на страницы руководства, и доступен infoв браузере или в виде HTML.
Жиль "ТАК - перестань быть злым"
8

Это может случиться с различными программами, например, у меня такое поведение было когда-то при использовании cp file /dev/null; вместо оценки скорости чтения с моего диска команда вернулась через несколько миллисекунд.

Насколько я помню, это было в Solaris или AIX, но этот принцип применим ко всем видам Unix-Y систем.

В старые времена, когда программа копировала файл куда-то, она чередовалась между readвызовами, которые получают данные с диска (или с тем, на что ссылается дескриптор файла) в память (с гарантией, что все будет там, когда readвернется) и writeвызовами (которые берут кусок памяти и отправляют контент по назначению).

Тем не менее, есть как минимум два новых способа достижения того же:

  • В Linux есть системные вызовы copy_file_range(вообще не переносимые на другие юниксы) и sendfile(несколько переносимые; изначально предназначенные для отправки файла в сеть, но теперь они могут использовать любой пункт назначения). Они предназначены для оптимизации переводов; если программа использует один из них, вполне возможно, что ядро ​​распознает цель /dev/nullи превращает системный вызов в неоперативный

  • Программы могут использовать mmapдля получения содержимого файла вместо этого read, это в основном означает «убедиться, что данные есть, когда я пытаюсь получить доступ к этой части памяти» вместо «убедиться, что данные есть, когда системный вызов вернется». Таким образом, программа может получить mmapисходный файл, а затем вызвать writeэтот фрагмент отображенной памяти. Однако, поскольку запись /dev/nullне требует доступа к записанным данным, условие «убедитесь, что оно есть» никогда не запускается, в результате чего файл также не читается.

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

Гунтрам Блом поддерживает Монику
источник
Я думаю, что смысл в tarинформационной странице GNU (см. Другой ответ) состоит в том, что у него есть специальный режим для этого, который, по-видимому, просто статистика файлов без их открытия. На самом деле я только что проверил tar cf /dev/null foo*пару файлов, и да, просто newfstatat(..., AT_SYMLINK_NOFOLLOW)системные вызовы, даже не те, open()которые могут обновить atime. Но +1 для описания механизмов, где это может произойти, без необходимости специально обнаруживать это.
Питер Кордес
Должно ли объяснение mmap читать «доступ к прочитанным данным» вместо «доступ к записанным данным?»
Уэйн Конрад
Смотрите также splice(2)о Linux. На самом деле, замена cat > /dev/nullна pv -q > /dev/null(которая используется splice()в Linux), скорее всего, уменьшит накладные расходы. Или dd bs=65536 skip=9999999999 2> /dev/null, или wc -c > /dev/nullили tail -c1 > /dev/null...
Стефан Шазелас