дд: несколько входных файлов

14

Мне нужно объединить куски из двух файлов:

если бы мне нужно было объединить целые файлы, я мог бы просто сделать

cat file1 file2 > output

Но мне нужно пропустить первые 1 МБ из первого файла, и мне нужно только 10 МБ из второго файла. Похоже, работа для dd.

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

Есть ли возможность сделать это за один шаг? т.е. без необходимости сохранять промежуточные результаты? Могу ли я использовать несколько входных файлов в dd?

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

Ответы:

21

dd можете написать в стандартный вывод тоже.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
meuh
источник
Это, наверное, лучший способ. Выходной файл не закрывается / повторно открывается (как это было с oflag=append conv=notrunc), поэтому файловые системы, которые выполняют отложенное размещение (например, XFS), с наименьшей вероятностью решат, что файл готов к записи, когда еще многое предстоит сделать.
Питер Кордес
@PeterCordes - это хорошая точка зрения, но пока ddее не просят sync, отсроченное распределение в любом случае не должно начинаться немедленно (если только память не ограничена, в этом случае ни один из методов не откладывает выделение).
Стивен Китт
@StephenKitt: Вы, вероятно, правы. Я размышлял о спекулятивном предварительном распределении XFS , где действительно нужно специально определять закрытый / вновь открываемый шаблон доступа (иногда наблюдаемый для файлов журнала).
Питер Кордес
3
В оболочках , как bashи mkshчто не оптимизируют из вил для последней команды в субоболочке, вы можете сделать его немного более эффективным путем замены подоболочки с командной группой. Для других оболочек это не должно иметь значения, и подход подоболочек может быть даже несколько более эффективным, поскольку оболочке не требуется сохранять и восстанавливать стандартный вывод.
Стефан Шазелас
10

Я не думаю, что вы можете легко прочитать несколько файлов за один ddвызов, но вы можете добавить, чтобы создать выходной файл в несколько шагов:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

Вам нужно указать оба conv=notruncи oflag=append. Первый избегает усечения вывода, второй начинает запись с конца существующего файла.

Стивен Китт
источник
8

Имейте в виду , что ddявляется низкоуровневым интерфейсом к read(), write()и lseek()системный вызов. Вы можете надежно использовать его только для извлечения фрагментов данных из обычных файлов, блочных устройств и некоторых символьных устройств (например /dev/urandom), то есть файлов, для которых read(buf, size)гарантированно будет возвращаться, sizeпока не достигнут конец файла.

Для каналов, сокетов и большинства символьных устройств (таких как ttys) у вас нет такой гарантии, если вы не read()используете размер 1 или не используете ddрасширение GNU iflag=fullblock.

Так что либо:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

Или:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

Или с оболочками со встроенной поддержкой оператора поиска, например ksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

Или zsh(если вы headподдерживаете -cопцию здесь):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
Стефан Шазелас
источник
Вам действительно нужны цитаты? Разве результат не всегда будет целым числом?
Стивен Пенни
@StevenPenny, оставляя расширение без кавычек, просит, чтобы оболочка раскололась, и это не имело бы никакого смысла. Разделение выполняется на текущее значение $IFS. Это независимо от содержимого переменной / расширения. См. Также последствия для безопасности, связанные с забыванием заключать в кавычки переменную в оболочках bash / POSIX
Стефан Шазелас
@ Stéphane Chazelas - в первом примере вы используете gddвместо dd. Это опечатка, или это намеренно?
Мартин Вегтер
3

С bash ism и функционально «бесполезным использованием cat », но наиболее близким к синтаксису, который использует OP:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(При этом ответ Стивена Китта представляется наиболее эффективным из возможных).

АРУ
источник
3
Строго говоря, <(...)это кшизм, который и так zshи bashскопировал.
Стефан Шазелас