du дает два разных результата для одного файла


23

Я аспирант вычислительной химии с доступом к кластеру Linux. Кластер состоит из очень большого (25 ТБ) файлового сервера, к которому подключено несколько десятков вычислительных узлов. Каждый вычислительный узел состоит из 8–24 ядер Intel Xeon. Каждый вычислительный узел также содержит локальный диск объемом около 365 ТБ.

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

Итак, я запускаю симуляции на локальных дисках, а затем, после их завершения, копирую файлы траектории - я запускаю симуляции молекулярной динамики (MD) - на файловый сервер для хранения. Предположим, у меня есть файл траектории, который называется traj.trrв каталоге на локальном диске узла /home/myusername/mysimulation1/traj.trr. Для длительного хранения я всегда копирую traj.trrв каталог на файловом сервере ~/mysimulation1/traj.trr, где ~представляет мой каталог на файловом сервере /export/home/myusername. После его копирования я обычно использую, du -hчтобы убедиться, что у /home/myusername/mysimulation1/traj.trrнего тот же размер файла, что и у ~/mysimulation1/traj.trr. Таким образом, я могу быть по крайней мере достаточно уверенным, что передача на файловый сервер прошла успешно. Например:

cd /home/myusername/mysimulation1/
cp -v traj.trr ~/mysimulation1/
du /home/myusername/mysimulation1/traj.trr -h
du ~/mysimulation1/traj.trr -h

Если два вызова du -hдают одинаковый читаемый человеком размер файла, то я могу быть вполне уверен, что передача / копирование прошло успешно. ( traj.trrРазмер моих типичных файлов варьируется от 15 до 20 ГБ, в зависимости от того, какую именно симуляцию я запустил.) Если я запускаю du(т.е. без -hпереключателя) два traj.trrфайла, их размеры в байтах обычно очень и очень похожи - - обычно в течение нескольких байтов. Я использовал этот общий метод в течение последних полутора лет, без проблем.

Однако в последнее время я столкнулся со следующей проблемой: иногдаdu -hсообщает, что дваtraj.trrфайла различаются по размеру на несколько ГБ. Вот пример:

cd /home/myusername/mysimulation1/            # this is the local disk
cp -v traj.trr ~/mysimulation1/
du traj.trr -h
cd ~/mysimulation1/                           # this is the fileserver
du traj.trr -h

Вывод из двух вызовов к du -hвыглядит следующим образом:

20G     traj.trr
28G     traj.trr

Я полагаю, что первый (т. Е. traj.trrЛокальный диск /home/myusername/mysimulation1/) имеет правильный размер файла, так как мои траектории симуляции, как ожидается, будут примерно от 15 до 20 ГБ каждая. Но тогда как на самом деле файл на файловом сервере может быть больше ? Я мог видеть, как это могло быть меньше, если так или иначе cpпередача не удалась. Но я не понимаю, как это может быть на самом деле больше .

Я получаю похожий вывод, когда выполняю те же команды, что и выше, но без -hпереключателя du:

20717480        traj.trr
28666688        traj.trr

Можете ли вы придумать причину такой разницы?

Если по какой-то маловероятной случайности duчто-то не работает, я могу согласиться с этим. Но мне просто нужно убедиться, что копия traj.trrна файловом сервере завершена и идентична его исходной версии на локальном диске. Мне нужно удалить локальный файл, чтобы у меня было достаточно места на локальном диске для запуска новых симуляций, но я не могу позволить себе traj.trrиспортить версию на файловом сервере.

Формат .trr файла (из пакета молекулярной динамики Gromacs) представляет собой бинарный формат, а не текст. Таким образом, я не уверен, что файлы могут быть надежно сопоставлены такой программой, как diff.


5
Попробуйте запустить md5sumили sha1sumна файлы. Они совпадают?
CJM

2
@cjm Я только что запустил md5sumдва файла. Две контрольные суммы совпадают. Итак, я думаю, это означает, что два файла одинаковы?
Андрей

3
Какие размеры указаны ls -l? Команда duсообщает, сколько места на диске используется для вашего файла, а не размер вашего файла. Размер диска может зависеть от вашей файловой системы и стратегий ее размещения.
Кейси

2
@casey ls -l -hговорит, что оба файла имеют размер 20 ГБ. Аналогично, ls -lговорится, что оба файла имеют размер 21214683940 байт. Поэтому я предполагаю, что файлы имеют одинаковый размер, но не занимают одинаковое количество дискового пространства (согласно du).
Эндрю

2
@ Андрей, учитывая, что размеры, сообщаемые ls, одинаковы, а хеши одинаковы, можно сделать вывод, что файлы одинаковы. Эти инструменты дают вам уверенность, в которой вы нуждаетесь, и показывают, что du - это не инструмент для удовлетворения ваших потребностей.
Кейси

Ответы:


32

Вы действительно должны использовать что-то вроде md5sumили sha1sumдля проверки целостности.

Если вы действительно хотите использовать размер, используйте ls -lили du -b.

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

Пример:

$ truncate -s 512M foo
$ cat foo >bar
$ ls -l foo bar
-rw-r--r-- 1 michas users 536870912 23. Dez 00:06 bar
-rw-r--r-- 1 michas users 536870912 23. Dez 00:03 foo
$ du foo bar
0       foo
524288  bar
$ du -b foo bar
536870912       foo
536870912       bar

У нас есть два файла, каждый из которых содержит 512 МБ нулей. Первый хранится разреженно и не использует места на диске, а второй явно хранит каждый байт на диске. - Тот же файл, но совершенно другое использование диска.

-bВариант может быть хорошо для вас:

   -b, --bytes
          equivalent to '--apparent-size --block-size=1'

   --apparent-size
          print apparent sizes, rather than disk usage; although the apparent
          size is  usually  smaller,  it  may  be  larger  due  to  holes  in
          ('sparse')  files, internal fragmentation, indirect blocks, and the
          like

8

Это общая проблема, когда вы помещаете одни и те же данные на 2 разных жестких диска. Вы захотите выполнить duкоманду с дополнительным ключом и, если он у него есть - что следует сделать, это узлы Linux.

Переключатель?

   --apparent-size
          print  apparent  sizes,  rather  than  disk  usage;  although the 
          apparent size is usually smaller, it may be larger due to holes in
          ('sparse') files, internal fragmentation, indirect blocks, and the 
          like

пример

$ du -sh --apparent-size /home/sam/scsconfig.log ~/scsconfig.log 
93K /home/sam/scsconfig.log
93K /root/scsconfig.log

Вышеуказанные файловые системы представляют собой локальный диск ( /root), а другая /home/sam- общий ресурс NFS с моего NAS.

$ df -h . /home/sam
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                      222G  118G   92G  57% /
mulder:/export/raid1/home/sam
                      917G  566G  305G  65% /home/sam

Так в чем дело?

Это сбивает с толку многих людей, но помните, что когда файлы хранятся на диске, они занимают блоки пространства, даже если они используют только часть этих блоков. При запуске duбез --apparent-sizeразмера вы получаете размер, основанный на объеме используемого дискового пространства на диске, а не на фактическом пространстве, занимаемом файлом (ами).

вместо этого использовать контрольную сумму?

Это, вероятно, лучший вариант, если вы хотите сравнить 2 дерева файлов. Вы можете использовать эту команду для вычисления контрольной суммы для всех файлов, а затем рассчитать окончательную контрольную сумму контрольных сумм. Этот пример использует, sha1sumно вы можете использовать его так же легко md5sum.

$ cd /some/dir
$ find . -type f \( -exec sha1sum "{}" \; \) | sort -k2,2 | sha1sum

пример

$ cd ~/dir1
$ find . -type f \( -exec sha1sum "{}" \; \) | sort -k2,2 | sha1sum
55e2672f8d6fccff6d83f0bffba1b67aeab87911  -

$ cd ~/dir2
$ find . -type f \( -exec sha1sum "{}" \; \) | sort -k2,2 | sha1sum
55e2672f8d6fccff6d83f0bffba1b67aeab87911  -

Итак, мы можем видеть, что 2 дерева идентичны.

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


5

Краткий ответ: не проверяйте размер файла, проверьте состояние возврата команды. Статус возврата является единственным надежным показателем того, была ли копия успешной (если не считать сравнения двух файлов побайтно, прямо или косвенно - что является избыточным, если копирование выполнено успешно).

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

Все команды Unix возвращают статус, указывающий, успешно ли они выполнены: 0 для успеха, 1 или больше для ошибок. Так что проверьте статус выхода cp. cpобычно выдает сообщение об ошибке, если оно не удалось, с указанием, что это за ошибка. В сценарии состояние выхода последней команды находится в магической переменной $?.

cp -v traj.trr ~/mysimulation1/
if [ $? -ne 0 ]; then
  echo 1>&2 "cp failed due to the error above"
  exit 2
 fi

Вместо проверки, $?является ли ноль, вы можете использовать логические операторы.

cp -v traj.trr ~/mysimulation1/ || exit 2

Если вы запускаете сценарий и хотите, чтобы сценарий был остановлен, если какая-либо команда не выполнена, запустите set -e. В случае сбоя какой-либо команды (т. Е. Возвращает ненулевой статус), скрипт немедленно завершится с тем же статусом, что и команда.

set -e
…
cp -v traj.trr ~/mysimulation1/

Что касается причины, по которой ваш скопированный файл был больше, это должно быть потому, что это был разреженный файл . Разреженный файл - это грубая форма сжатия, где блоки, содержащие только нулевые байты, не сохраняются. Когда вы копируете файл, cpкоманда читает и записывает нулевые байты, поэтому там, где в оригинале отсутствовали блоки, копия имеет блоки, заполненные нулевыми байтами. В Linux cpкоманда пытается обнаружить разреженные файлы, но это не всегда удается; cp --sparse=alwaysзаставляет его стараться из-за очень небольшого увеличения процессорного времени.

В более общем случае duможет возвращать разные результаты из-за других форм сжатия. Сжатые файловые системы встречаются редко. Если вы хотите узнать размер файла, например, количество байтов в файле, а не количество используемых дисковых блоков, используйте ls -lвместо du.


Спасибо! Знаете ли вы, есть ли (отдельная) утилита, которая может сказать мне, является ли мой файл разреженным?
Эндрю

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.