我想从非常大的 tar.gz 存档中提取几个目录(假设aaa
, bbb
, ccc
)。
ccc
有时存在,有时不存在,但我想避免在提取过程中失败。
是否可以从 tar 存档中提取准确的目录列表,并且如果其中一些目录不存在也不会失败?
tar -xzf file.tar.gx --wildcards aaa bbb ccc
如果存档中不存在任何位置,则命令会失败。
答案1
一种选择是使用pax
标准命令来提取 tar 档案,并使用该-'s/regexp/replacement/
选项从选择中删除我们不需要的成员:
<file.tar.gz gunzip |
pax '-s:'{aaa,bbb,ccc}':&:' \
'-s:.*::' -r
这个想法是,对于路径中包含aaa
,bbb
或ccc
的所有存档成员,我们将它们替换为相同的,因此无操作,但这会导致在存在匹配时跳过下一个替换,特别是s:.*::
具有丢弃存档成员的效果。
要查看将提取的内容,您可以删除-r
.将标志添加p
到替换中,以便获取正在进行哪些替换的报告。
请注意,pax
至少在 Debian/Ubuntu 上发现的 MirBSD 实现中,我发现如果存在符号链接的存档成员,如果符号链接目标与模式不匹配(即使它们的路径匹配),它们将被丢弃。看https://austingroupbugs.net/view.php?id=1618目前正在讨论在这方面改进 API 的地方。
答案2
tar
据我所知,GNU 和 BSD命令不支持这一点,但是:
如果tar
存档足够小或者无法从介质上读取,则回卷的成本很高(实际的磁带档案),您可以list_of_matching_files=$(tar -tf file.tar.gz | grep '(aaa|bbb|ccc)')
编译文件列表。您不会喜欢当文件名包含换行符时发生的情况,这是完全合法的。
因此,这将使您(至少在 GNU 中tar
)可以选择使用该选项对每个已执行的文件执行命令--to-command=
。tar
将设置TAR_REALNAME
环境变量,您的程序可以使用该环境变量来选择是否将通过管道传输的数据写入具有适当名称的文件,或者只是忽略。然后,您还应该处理TAR_**
设置为正确处理文件/目录类型、所有者、模式和日期的其他环境变量。简而言之,除了阅读(相当愚蠢的).tar
格式之外,您还可以tar
在自己的程序/shell 脚本中完成工作。
或者,老实说,由于无论如何都需要按顺序读取 tar,并且存储通常很便宜,因此只需提取所有内容,在途中记下提取的文件,然后删除“错误”的文件。
或者,可能值得尝试一下,7z
当模式不匹配时,提取 tar 文件是否也会中止。
最后:每种适当的编程语言都可能有一个tar
消耗库。可能真的值得六行Python,请参阅第二个例子来自官方文档:
#!/usr/bin/env python3
import os
import tarfile
def py_files(members):
for tarinfo in members:
"""
modify this check: only `yield tarinfo` if the
tarinfo.name matches your needs. Conveniently,
python has string functions like `tarinfo.name.startswith("foo")`
and a capable regex library
"""
if os.path.splitext(tarinfo.name)[1] == ".py":
yield tarinfo
tar = tarfile.open("sample.tar.gz")
tar.extractall(members=py_files(tar))
tar.close()
答案3
无论错误如何,tar
都会提取其他文件。如果您不关心该错误,请忽略它。发送stderr
至/dev/null
且不测试返回码$?
。
tar -xzf file.tar.gz files 2> /dev/null
如果您需要顺序运行命令,请使用;
而不是&&
.
tar ... ; ...