从 Tar 存档中提取特定文件时如何指定目标位置?

从 Tar 存档中提取特定文件时如何指定目标位置?

根据新信息,我重新表述了这个问题。下面是旧信息,以免使基于旧信息的答案和评论无效。

我有一个tarball.tar想要提取的tarball destination,该目录与我当前的工作目录不同,因此我使用 tar 的-C选项,它可以实现我想要的功能。

但是,如果我尝试指定要从 tarball 中提取的文件,则该-C选项似乎被忽略。文件被提取到我当前的工作目录中。

tar -xf tarball.tar -C destination

Tar 的版本是

$ tar --version
tar (GNU tar) 1.28

这是一个错误还是我的理解有-C误?

最小工作示例

下面是一个 bash 脚本来展示该行为。将其存储(或执行)在一个空目录中

#!/bin/bash -x
set -e                                 # Abort if any of these commands fails

touch file1 file2 file3                # Create files to be archived
tar -cf tarball.tar file1 file2 file3  # Create the archive
rm file1 file2 file3                   # Remove source files
tar -tf tarball.tar                    # Should contain files 1–3

mkdir -p destination                   # Create destination directory
tar -xf tarball.tar file1 file2 -C destination # Extract two files from 
                                       #+ tarball into destination directory

ls .                                   # Should contain only the script itself,
                                       #+ tarball.tar, and destination
ls destination                         # Should contain file1 and file 2

如果我执行脚本,destination则为空并ls .返回

$ ls .
file1 file2 tarball.tar tar.sh

如果我没有指定要提取的文件(因此 tar -xf tarball.tar file1 file2 -C destination 第 9 行变成 tar -xf tarball -C destination),则行为将符合预期。ls destination显示file1 file2 file3

老问题(忽略此问题)

我有一个 tar 档案/path/to/backup.tar.gz,其中包含目录home/bleistift2/stuffhome/bleistift2/more_stuff

为了将这两个目录提取到/home/bleistift2/tmp(文件系统中,而不是存档中),我发出以下命令。我的理解是-C指定提取位置。目标目录存在。

tar -zxvf /path/to/backup.tar.gz \                 # The archive to extract
home/bleistift2/stuff home/bleistift2/more_stuff \ # The contents to extract
--same-owner -C /home/bleistift2/tmp               # The destination directory

但是,目录是作为档案的兄弟存储的,因此我最终使用了/path/to/home/bleistift2/{stuff, more_stuff}而不是/home/bleistift2/tmp/home/bleistift2/{stuff, more_stuff}

答案1

-C工作原理如下cd

$ tar -tf test.tar
a
b
$ ls -Al dst1/
total 0
$ ls -Al dst2/
total 0
$ tar -xvf test.tar -C dst1/ a -C ../dst2/ b
a
b
$ rm -v dst*/*
removed 'dst1/a'
removed 'dst2/b'
$ (TAR=$(realpath test.tar); cd dst1/; tar -xvf "$TAR" a; cd ../dst2/; tar -xvf "$TAR" b)
a
b
$ rm -v dst*/*
removed 'dst1/a'
removed 'dst2/b'
$

是的,顺序很重要。

答案2

更新:这个答案是在编辑问题之前按照理解解决问题的,所以事实证明它不是所报告的实际问题的答案。我很快就会删除这个答案。


tar 提取的文件将包含完整路径名,从开始提取的地方开始。

因此,如果文件存储在名为 的 tarball 中home/bleistift2/stuff,并且您将其解压缩到 下/home/bleistift2/tmp/,那么您最终会得到/home/bleistift2/tmp/home/bleistift2/stuff,因为 tar 没有很好的方法来知道您想要在解压缩过程中删除主目录前缀......

您可以通过向 tar 传递--strip-components选项来控制提取过程中的此行为。

来自tar(1) 手册页

--strip-components=数字

数字提取文件名中的前导组件

在您的具体情况下:

$ tar -zxvf /path/to/backup.tar.gz \
    home/bleistift2/stuff home/bleistift2/more_stuff \
    --same-owner -C /home/bleistift2/tmp \
    --strip-components=2

删除 2 个组件将删除基本home/目录以及用户的主目录。这似乎正是您在特定情况下想要的。


作为更一般的建议,尝试防止在创建时解决这个问题,通过不存储 tarball 中不相关或不需要的文件路径部分,这在提取时非常有用。

不要使用绝对路径(或根目录的完整路径):

$ tar -czvf /path/to/backup.tar.gz /home/bleistift2

将目录更改为主目录并打包当前目录:

$ cd /home/bleistift2
$ tar -czvf /path/to/backup.tar.gz .

这样,文件将作为档案存储./stuff./more_stuff档案内,并且您在提取时无需剥离任何组件。

您还可以使用-C选项来更改目录,这相当于上面的命令:

$ tar -czvf /path/to/backup.tar.gz -C /home/bleistift2 .

相关内容