我们有一个 cpio 存档,它是通过生成一个文件创建的,该文件包含要包含在存档中的绝对路径列表。 (纯文本文件的每行一个绝对路径)生成存档的命令本质上是:
cat list-of-files | cpio -ocvB > preserved.cpio
我们稍后需要从该存档中提取文件。我们再次想要使用一个包含要提取的文件列表的文件(存档中所有文件的某个子集,同样采用纯文本文件每行一个绝对路径的格式)。
cpio -icuBdmv `cat files-to-extract` < preserved.cpio
除非其中一个路径包含空格,否则这种方法可以正常工作。生成存档很好,但是在提取文件时,名称中带有空格的任何文件都会被静默跳过。中的所有其他路径files-to-extract
均已成功提取。
我一直在控制台上玩游戏,试图想出一些方法来解决这个问题,但没有成功。如果我指定名称中包含空格的单个文件并将其用引号引起来,则该文件将成功提取:
# This extracts the file successfully
cpio -icuBdmv "/foo/bar/some file.txt" < preserved.cpio
因此,我可以files-to-extract
循环读取并一次提取每个文件,但这些存档可能很大(多个 GB),因此速度非常慢。
我尝试了一些方法来尝试转义文件路径中的空格或引用每个路径值,但我尝试过的任何方法都不起作用。
# Still skips the file with spaces:
cpio -icuBdmv `cat files-to-extract | sed 's/ /\\ /'` < preserved.cpio
# Extracts no files, even the ones without spaces:
cpio -icuBdmv `cat files-to-extract | sed 's/\(.*\)/"\1"/'` < preserved.cpio
如果能够通过一次 cpio 运行来完成此提取,而不必一次循环并提取一个文件,那真是太好了。我确信这只是我如何向 cpio 提供这些值的问题,但我一生都无法弄清楚为什么。
可能不相关,但只是为了完整性:这是在 CentOS 7.2 上,使用 GNU cpio 2.11
答案1
cpio
有一个-E
( --pattern-file
) 选项,它允许您从文件中读取文件名列表,而不是(或同时)在命令行上提供文件名。例如:
cpio -icuBdmv -E files-to-extract < preserved.cpio
cpio
还必须-F
指定存档名称(而不是使用 stdin/stdout)。 -I
和-O
类似,但分别代替 stdin 或 stdout 工作。
例如,您可以指定存档-F
并在标准输入上提供文件列表:
cpio -icuBdmv -F preserved.cpio < files-to-extract
或同时使用-E
和-F
cpio -icuBdmv -E files-to-extract -F preserved.cpio
顺便说一句,对于许多 GNU 程序(包括cpio
),手册页几乎毫无用处,但它们在 .info 文件中有详细记录。在某些 Linux 发行版上,信息文档通常是单独的包(例如在 debian 上cpio-doc
),因此您将需要安装它们以及信息阅读器(例如 GNUinfo
或pinfo
)
无论如何,这里有一些cpio
信息页面的相关摘录:
-E FILE
,--pattern-file=FILE
读取指定要从 FILE 中提取或列出的文件名的其他模式。 FILE 行被视为 cpio 的非选项参数。该选项用于拷入模式,
和
-F ARCHIVE
,--file=ARCHIVE
用于代替标准输入或输出的存档文件名。要使用另一台计算机上的磁带驱动器作为存档,请使用以 开头的文件名
HOSTNAME:
,其中 HOSTNAME 是计算机的名称或 IP 地址。@
如果您有权限(通常是该用户~/.rhosts
文件中的条目),则主机名前面可以带有用户名和用于以该用户身份访问远程磁带驱动器的用户名。
答案2
文件名中的空格可能很棘手,但我认为这可能会有所帮助。
不要cat
提取要提取的文件,而是尝试通过用xargs
NULL 字符替换 EOL 来提供它。
就像是
tr '\n' '\0' < list-of-files | xargs -0 -I{} sh -c 'cpio -icuBdmv "{}" < preserved.cpio'
应该可以解决问题。