最近经常遇到dd
和cpio
两个命令,觉得很有必要写篇文章强化下记忆。
dd
命令
用途和命名
dd
命令的用途是拷贝和转换文件。这个可以通过man dd
知道:
dd - convert and copy a file
通过info dd
命令可以得到一段不同的说明:
`dd' copies a file (from standard input to standard output, by default)
with a changeable I/O block size, while optionally performing
conversions on it.
总的来说,dd
命令就是按照每次一块的方式来拷贝文件,同时在拷贝的过程中还能对内容进行转换。
至于dd
命令为啥叫这个名字,通过查询wifi页面可知,dd
可能是data description的缩写:
The name dd may be an allusion to the DD statement found in IBM's Job Control Language (JCL),[3] where the initials stand for "Data Description.
拷贝数据
dd
经常被用来拷贝数据,从一个地方拷贝到另一个地方。为啥不用copy
就好?因为I/O操作(尤其是磁盘I/O)都是基于块的,因此dd
提供的基于块的数据拷贝操作有性能上的优势。我们通过下面的例子来看
~/programming/test$ dd bs=K if=/dev/zero of=/dev/null
16759236+0 records in
16759236+0 records out
17161457664 bytes (17 GB) copied, 22.5896 s, 760 MB/s
~/programming/test$ dd bs=b if=/dev/zero of=/dev/null
17889445+0 records in
17889445+0 records out
9159395840 bytes (9.2 GB) copied, 23.565 s, 389 MB/s
在上面的例子中,我们将数据从/dev/zero
拷贝到/dev/null
,两次拷贝指定不同的块大小,第一次bs=b
(b是512字节),第二次指定bs=K
(K是1024字节),可见块大的拷贝性能高。但是,实际情况肯定不是块越到拷贝性能越好,针对不同的设备应该会有不同的最优值,我不是这方面的专家,这里就不展开了。
常用选项
if=FILE: 输入文件,默认是stdin
of=FILE: 输出文件,默认是stdout
bs=BYTES: 指定块大小,默认是b,也就是512字节。
count=N: 拷贝块的数量,count * bs就是拷贝的总字节数
上面的选项是最常用的,因为拷贝的过程一半就是需要三个参数:源、目的和大小。下面是几个示例,从wifi搬过来的:
# 写1G的空数据到一个文件,再读出来,用来测试读写性能
$dd if=/dev/zero of=file_1GB bs=K count=MB
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 3.67137 s, 279 MB/s
$dd if=file_1GB of=/dev/null bs=K count=MB
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 1.49088 s, 687 MB/s
上面的数据是我的固态硬盘的真实数据。
转换数据
dd
命令还有两个参数是conv和cbs:
conv: 转换操作,执行一些指定的转换操作,所有的操作可以看man手册
cbs:每次转换的块大小,有些conv操作必须指定cbs的值(比如block操作),有些则不用(比如ucase)操作。
举个最简单的例子,把一个文件的内容都转换成大写:
$dd if=log conv=ucase
WRITE
HELLO, WORLD
HELLO, WORLD
常见应用
我经常见到的,也是我本人常用的,是用dd
命令来生成一个指定大小的全0文件,然后将其格式化为ext文件系统后挂载,这样就能添加文件到这个文件系统中了。
cpio
命令
cpio
也是GNU旗下的一个工具,主要用来将文件拷贝到归档文件或者是从归档文件中将文件拷贝出来,这里说的归档文件指的是cpio格式的文件 。cpio
的man手册内容较少,可以查看在线帮助页面获取更多信息。从官网的手册上可以看到cpio
还可以用于软盘和磁带,不过现在一般是用不上了。
cpio
有以下三种工作方式:
Copy-out mode: 将指定的文件拷贝到归档文件中,也就是生成归档文件
Copy-in mode: 将指定的文件从归档文件中拷贝出来,默认是解压所有文件,也可以只解压指定的文件
Copy-pass mode: 将文件从一个目录拷贝到另一个目录
Copy-out mode
Copy-out模式从标准输入读取要存档的文件列表,默认格式是每行一个文件,以换行符区分(也可以使用--null选项,改成以空字符区分),将文件打包成一个存档文件输出到标准输出,不过我们一般是用管道来和cpio程序打交道。下面的例子将目录d中的文件打包成d.cpio:
~/temp$ ll d
total 8
-rw-rw-r-- 1 diabloneo diabloneo 7 Aug 7 22:30 a
-rw-rw-r-- 1 diabloneo diabloneo 6 Aug 7 22:30 b
~/temp$ find d | cpio -o > d.cpio
1 block
~/temp$ ll
total 8
drwxrwxr-x 2 diabloneo diabloneo 4096 Aug 7 22:32 d/
-rw-rw-r-- 1 diabloneo diabloneo 512 Aug 7 22:34 d.cpio
注意,生成的d.cpio文件的大小,是512,但是打包进去的目录和文件没有这么大。原因是cpio
程序也是根据块来进行I/O操作的,默认的块大小是512,要更改这个块大小,可以使用-C参数。
Copy-in mode
Copy-in模式从标准输入读入一个归档文件,然后拷贝出所有的或者指定的文件,也可以只列出归档文件中的文件列表。
列出归档文件中的内容:
~/temp$ cpio -t < d.cpio
d
d/a
d/b
1 block
解压归档文件到目录c:
~/temp$ mkdir c
~/temp$ cd c
~/temp/c$ cpio -i < ../d.cpio
1 block
~/temp/c$ ll
total 4
drwxrwxr-x 2 diabloneo diabloneo 4096 Aug 7 22:46 d/
~/temp/c$ ll d
total 8
-rw-rw-r-- 1 diabloneo diabloneo 7 Aug 7 22:46 a
-rw-rw-r-- 1 diabloneo diabloneo 6 Aug 7 22:46 b
Copy-pass mode
Copy-pass模式就把文件从一个目录拷贝到令一个目录:
~/temp$ mkdir e
~/temp$ find d | cpio -p e
1 block
~/temp$ ll e
total 4
drwxrwxr-x 2 diabloneo diabloneo 4096 Aug 7 22:51 d/
~/temp$ ll e/d
total 8
-rw-rw-r-- 1 diabloneo diabloneo 7 Aug 7 22:51 a
-rw-rw-r-- 1 diabloneo diabloneo 6 Aug 7 22:51 b
归档文件格式
cpio
有一个--format选项用于指定创建归档文件时所用的格式,即copy-out模式使用的格式。Copy-in模式自动识别格式,无需指定。官方手册里列出了好几种格式,这里不一一列出,不过要说明一下cpio
创建的归档文件对归档文件大小以及inode数量都有限制。默认使用的格式是bin格式,支持2G大小的归档文件,inode数量不能超过6K个。对于归档整个文件系统,可以使用newc格式,支持4G大小的归档文件,以及大于6K的inode数量。当然,不同格式的大小也有所不同,下面是bin格式、newc格式和ustar格式的归档大小比较(都是对前面的d目录进行归档):
~/temp$ ll
total 16
drwxrwxr-x 2 diabloneo diabloneo 4096 Aug 7 22:32 d/
-rw-rw-r-- 1 diabloneo diabloneo 512 Aug 7 22:37 d.cpio
-rw-rw-r-- 1 diabloneo diabloneo 512 Aug 7 23:00 d-newc.cpio
-rw-rw-r-- 1 diabloneo diabloneo 3584 Aug 7 23:00 d.tar
常见应用
cpio
一般用来存档整个文件系统,在为各种基于Linux的嵌入式系统创建初始的rootfs的时候经常会用到。