使用 cpio 提取文件,其中一个或多个路径可能包含空格

使用 cpio 提取文件,其中一个或多个路径可能包含空格

我们有一个 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),因此您将需要安装它们以及信息阅读器(例如 GNUinfopinfo

无论如何,这里有一些cpio信息页面的相关摘录:

-E FILE,--pattern-file=FILE

读取指定要从 FILE 中提取或列出的文件名的其他模式。 FILE 行被视为 cpio 的非选项参数。该选项用于拷入模式,

-F ARCHIVE,--file=ARCHIVE

用于代替标准输入或输出的存档文件名。要使用另一台计算机上的磁带驱动器作为存档,请使用以 开头的文件名HOSTNAME:,其中 HOSTNAME 是计算机的名称或 IP 地址。@如果您有权限(通常是该用户~/.rhosts文件中的条目),则主机名前面可以带有用户名和用于以该用户身份访问远程磁带驱动器的用户名。

答案2

文件名中的空格可能很棘手,但我认为这可能会有所帮助。

不要cat提取要提取的文件,而是尝试通过用xargsNULL 字符替换 EOL 来提供它。

就像是

tr '\n' '\0' < list-of-files | xargs -0 -I{} sh -c 'cpio -icuBdmv "{}" < preserved.cpio'

应该可以解决问题。

相关内容