dd:多个输入文件


14

我需要串联两个文件中的块:

如果需要串联整个文件,我可以简单地做

cat file1 file2 > output

但是我需要从第一个文件中跳过第一个1MB,而我只希望从第二个文件中跳过10 MB。听起来像是工作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吗?

Answers:


21

dd 也可以写到stdout。

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

这可能是最好的方法。输出文件不会关闭/重新打开(就像使用一样oflag=append conv=notrunc),因此延迟分配的文件系统(例如XFS)最不可能在尚需处理的时候确定文件已被写入。
彼得·科德斯

@PeterCordes是个好主意,但是只要dd不被要求sync,延迟分配无论如何都不应立即生效(除非内存太紧,在这种情况下,任何一种方法都不会推迟分配)。
史蒂芬·基特

@StephenKitt:你可能是对的。我在想XFS的推测性预分配,它确实需要特别检测关闭/重新打开访问模式(有时在日志文件中看到)。
彼得·科德斯

3
在像这样的shell中,bash并且mksh不能优化子shell中最后一个命令的fork,可以通过用命令组替换subshel​​l使其效率更高。对于其他Shell,这无关紧要,由于外壳不需要保存和还原stdout,因此subshel​​l方法甚至可能稍微更高效。
斯特凡Chazelas

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=notruncoflag=append。第一个避免截断输出,第二个避免从现有文件的末尾开始写入。


8

请记住,dd是一个原始界面的read()write()lseek()系统调用。您只能可靠地使用它从常规文件,块设备和某些字符设备(例如/dev/urandom)中提取数据块,即只要不到达文件末尾,就read(buf, size)可以保证为其返回size文件。

对于管道,套接字和大多数字符设备(例如ttys),除非read()具有1的大小或使用GNU dd扩展名,否则没有任何保证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,未引用扩展名是要求shell对其进行split + glob,这在这里没有任何意义。分割部分是根据的当前值完成的$IFS。这与变量/扩展的内容无关。另见遗忘在bash / POSIX壳引用变量的安全隐患
斯特凡Chazelas

@StéphaneChazelas-在第一个示例中,您使用gdd而不是dd。这是错字,还是故意的?
Martin Vegter '16

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
严格来说,<(...)是一个既被复制又被复制的kshismzshbash
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.