考虑来自外部系统的单个 tar 文件,其中包含一些具有我想要保留的各种属性的目录,例如权限、mtimes 等。我如何轻松地将这些文件的子集作为普通用户(而不是 root)获取?
寻找类似的东西:
tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz
保留此 tar 存档中的主要属性(所有权、组、模式、mtime)也很重要。 tar 文件中的其他属性(例如扩展标题关键字?
如果该子目录包含巨大文件,则避免使用临时目录的解决方案的奖励点。
答案1
bsdtar(基于libarchive)可以从标准输入到标准输出过滤 tar(和其他一些档案)。例如,它可以仅传递匹配的文件名一个模式,并且可以s/old/new/
重命名。它已经针对大多数发行版进行了打包,例如Ubuntu。bsdtar
libarchive-tools
sudo apt-get install libarchive-tools # or aptitude, if you have it.
# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @- # filter stdin to stdout, with gzip compression of output.
请注意,输入/输出有多种压缩格式可供选择,因此您不必自己手动通过gunzip / lz4进行管道传输。您可以使用语法-
来使用 stdin @tarfile
,和/或-
像平常一样使用 stdout 。
我的搜索还发现了这个流式 tar 修改工具,它似乎希望您使用 javascript 定义所需的存档更改。 (我认为整个事情都是用js写的)。
答案2
最简单的方法是复制整个档案;我想你不想这样做,因为它太大了。
常用的命令行工具(tar
、pax
)不支持将一个存档的成员复制到另一个存档。
如果您不需要保留所有权,我建议使用保险丝文件系统。您可以使用存档挂载将存档安装为文件系统;对源存档执行此操作,并在已安装的文件系统上运行 tar。
archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt
或者,您可以使用AVFS:
mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz
或者,您可以tar
在原始存档上运行并通过以下方式提取到远程计算机SSHFS。
sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt
然而,如果您需要保留所有权,所有这些方法都很麻烦。它们都涉及提取到本地计算机上的文件,因此该文件的所有权必须是预期的偏僻的所有权。这需要以 root 身份运行,并且如果文件由本地计算机和远程主机之间的名称或 ID 不同的帐户拥有,则可能无法给出预期结果。
蟒蛇的tarfile
库提供了一种相当简单的方法来操作 tar 成员,因此您可以将它们从一个 tar 文件转移到另一个 tar 文件。它支持 POSIX 标准格式(ustar、pax)以及一些 GNU 扩展。这是一个未经测试的 Python 脚本,它在其标准输入上读取 tar 文件(可能使用 gzip 或 bzip2 压缩),并在其标准输出上写入使用 bzip2 压缩的 tar 文件。如果源中的成员以传递给脚本的参数开头,则会复制这些成员。
#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
if info.name.startswith(sys.argv[1]):
destination.addfile(info)
destination.close()
被调用为
tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj
答案3
GNUtar
确实有一个--delete
选项:
$ tar -c a b c | tar --delete a | tar -t
b
c
这样,您可以通过指定什么来获取输入 tar 的子集不是包含在输出中。
不幸的是,我无法获得--exclude
使用的选项--delete
,因此似乎您首先需要获取-t
要删除的内容的显式列表(),然后将其传递给另一个调用tar
。
$ tar --delete --no-recursion `tar -t --exclude subdir <some.tar` <some.tar | ssh ...
或者,如果列表太长或太复杂,您可以将列表存储在外部文件中:
$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...
答案4
据我所知,该tar
命令不能使用 tar 格式两个都作为输入和输出。您必须以某种方式在本地提取文件,然后再次使用 tar 来动态创建 tarfile,如下所示(这-
意味着使用标准输入/输出而不是文件):
tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'
请注意,能够tar
直接在另一个 tarfile 中提取 tarfile 是一个有趣的想法......