кот | противоречивое поведение

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

Если вы создаете файл со следующим.

echo test >testfile

Вывод следующей команды противоречив.

cat testfile /dev/zero | dd bs=256k count=1 status=none | od -c

Это выход, который я ожидал.

0000000   t   e   s   t  \n  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
1000000

Но вы также случайно получаете одно из следующего.

0000000   t   e   s   t  \n
0000005
0000000   t   e   s   t  \n  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0400000  \0  \0  \0  \0  \0
0400005

Почему эта команда имеет противоречивое поведение?

Даже если dd обрезает канал в конце первого файла, результат 128k странный. Я получаю те же противоречивые результаты в системах 16.04, 18.04 и 19.04.

3
задан 30 May 2019 в 02:25

2 ответа

Вам необходимо указать полные блоки. Попробуйте:

cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | od -c

Документация

Из man dd:

fullblock
& nbsp; & nbsp; & nbsp; & NBSP; & NBSP; & NBSP; накапливать полные блоки ввода (только iflag)

Пример

Заметьте, что без fullblock число байтов несовместимо:

$ cat testfile /dev/zero | dd bs=256k count=1 status=none | wc -c
5
$ cat testfile /dev/zero | dd bs=256k count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k count=1 status=none | wc -c
5

с iflag=fullbock, я вижу последовательные полные байты:

$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
$ cat testfile /dev/zero | dd bs=256k iflag=fullblock count=1 status=none | wc -c
262144
0
ответ дан 30 May 2019 в 02:25

Суть проблемы двояка. Одна часть проблемы - короткое или частичное read () . Согласно спецификациям POSIX :

Частичный входной блок - это блок, для которого read () вернул меньше размера входного блока.

Это типично для трубок, и именно это и происходит в вопросе. Одно из решений - использовать расширение GNU iflag = fullblock , и это версия, которую использует Ubuntu. Из GNU dd manual :

Обратите внимание, что если ввод может возвращать короткие чтения, как это могло бы иметь место при чтении из канала, например, 'iflag = fullblock' гарантирует, что 'count =' соответствует завершению входные блоки, а не традиционное поведение, указанное в POSIX, по подсчету операций чтения ввода.

POSIX dd , MirOS dd , FreeBSD dd - у них такой опции нет (хотя были запросы , чтобы добавить это в спецификацию POSIX). Итак, как мы можем писать переносимые сценарии с dd , которые вы, возможно, захотите перенести из Ubuntu, чтобы сказать FreeBSD? Что ж, отчасти проблема связана с флагом count = 1 . Он сообщает dd , сколько вызовов read () выполнить. Попробуйте выполнить несколько трассировок на dd if = / dev / urandom | strace -e read dd of = / dev / null bs = 256k count = 1 , и вы увидите, что всегда есть только один read () , который часто является частичным.(Обратите также внимание: не удивляйтесь, если вы увидите 262144 байта, прочитанные вместо 256000, потому что 256k равно 256 * 1024 = 262144)

Решение состоит в том, чтобы перевернуть параметры, то есть сделать размер блока bs = 1 и count = 256k . Таким образом мы гарантируем отсутствие частичного чтения и всегда читаем 1 байт, но мы сделаем это 256 тысяч раз. И да, это намного медленнее и займет намного больше времени с данными в диапазоне гигабайт / терабайт. В моих тестах iflag = fullblock был примерно в 100 раз быстрее (разница между 5 миллисекундами и 700 миллисекундами на 256 Кбайт). Однако преимущество в том, что это переносимо и не должно полагаться на расширение GNU dd , особенно вы не всегда можете установить GNU dd

2
ответ дан 9 December 2019 в 07:12

Другие вопросы по тегам:

Похожие вопросы: