从 tarball 中删除目录的跨平台方法

Cross-platform way to remove dir from tarball

我发现了这个: https://www.cyberciti.biz/faq/unix-linux-appleosx-bsd-tar-remove-directory/

tar --delete -f file.tar 'path1/dir1'

但这在 MacOS 上不起作用。我得到:

tar: Option --delete is not supported

我正在寻找适用于所有 *nix 风格的东西。有人知道这样做的好方法吗?也许我真的需要先解压并忽略该文件夹,然后重新压缩它?

简答

是的,如果您想要一个适用于许多 *nix flavors 的解决方案,那么您将不得不这样做;先解压,忽略文件夹,然后重新打包。


解决方案:

我会做如下事情:

# Path to source .tar
src_tar=/the/path/to/your/tarfile.tar

# Path to dir in .tar that you want to delete.
rm_tar_dir=path1/dir1

# Create a temporary dir for extracting the .tar contents into.
tmp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'tar-tmpdir')

# Extract all contents from the source .tar to a temporary dir
tar zxf "$src_tar" -C "$tmp_dir"

# Delete the unwanted dir from temporary dir.
rm -rf "${tmp_dir:?}/${rm_tar_dir}"

# Create new .tar archive, overwriting the original source .tar
tar czf "$src_tar" -C "$tmp_dir" .

# Clean up
rm -rf "$tmp_dir"

为什么我推荐上面显示的解决方案:

首先,(出于显而易见的原因)我无法测试并确认上述解决方案在所有 *nix flavors 上都能成功运行。其次,如果我不这么说就太天真了,因为(我相信你知道),这是一个古老的大景观,即有很多版本、口味和变体。

我根据以下 findings/research 得出了上面建议的解决方案。 *nix 的风格在下面的 support/compatibility table 中涵盖的远非详尽无遗。我从 here.

列出的口味中选择了它们

大多数选择的 flavours 是由志愿者团体开发的,并免费提供(Open BSD、Free BSD 等)。幸运的是,这些 *nix 风格 的文档、手册页等已在线发布,它们对我的决策产生了主要影响。 IBM AIX 和 Sun 的 Solaris 是例外,因为它们是专有的,但是这两者有一些文档、手册页等。


Support/Compatibility 表

  • tar --delete选项

    让我们先看看对 tar 命令 --delete 选项的支持。正如您在下面的 table 中看到的那样,它远未得到广泛支持 :( 因此,为什么似乎有必要采用更详细的解决方案 - 不幸的是,当需要跨平台时,我们不能使用 oneliner .

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ IBM │ Open │ Free │ Net │ Darwin/MacOS │ Linux │ Sun     │
                  │ AIX │ BSD  │ BSD  │ BSD │     BSD      │  GNU  │ Solaris │
    ┌─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │ --delete    │  x  │  x   │  x   │  √  │       x      │   √   │    x    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    
  • 其他tar选项

    上面提供的解决方案使用了几个 tar 选项,即; -z-x-f-c-C。正如您在下面的 table 中看到的那样,它们得到了广泛的支持。但是,值得注意的是 -z 选项(用于通过 gzip 过滤存档)在 IBM 的 AIX 上不受支持,据我所知,它在大型机上使用 -(因此,我的假设可能不是很多对你来说是一个破坏者。

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ IBM │ Open │ Free │ Net │ Darwin/MacOS │ Linux │ Sun     │
                  │ AIX │ BSD  │ BSD  │ BSD │     BSD      │  GNU  │ Solaris │
    ┌─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  -z         │  x  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  -x         │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  -f         │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  -c         │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  -C         │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  --exclude  │  x  │  x   │  √   │  √  │      √       │   √   │    x    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    

    tar --exclude选项

    请注意,在之前的 table 中,--exclude 选项似乎也没有得到广泛支持 - 因此我们不在建议的解决方案中使用它。在解压 .tar 时,我会避免选择排除不需要的目录(即您要删除的目录)。所以避免做这样的事情:

    # Don't do this....
    
    # Extract all contents from the source .tar to a temporary dir,
    # and exclude the directory that you effectively want to delete.
    tar zxf "path/to/tarfile.tar" --exclude "path1/dir1" -C "path/to/tmpdir"
    

    您会注意到在建议的解决方案中,我们解压所有内容(不排除),然后使用 rm -rf 删除不需要的目录,然后再重新打包。


  • 解决方案使用的其他命令

    下面的 table 显示了建议解决方案中使用的其余命令:

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ IBM │ Open │ Free │ Net │ Darwin/MacOS │ Linux │ Sun     │
                  │ AIX │ BSD  │ BSD  │ BSD │     BSD      │  GNU  │ Solaris │
    ┌─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  rm -rf     │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  mktemp     │  x  │  √   │  ?   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  mktemp -d  │  x  │  √   │  ?   │  √  │      √       │   √   │    √    │
    ├─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  mktemp -t  │  x  │  √   │  ?   │  √  │      √       │   √   │    √    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    

    如您所见,我们很好地利用了 rm -rf,因为它得到了很好的支持。

    谨慎mktemp...

    mktemp 和它的 -t-d 选项似乎没有得到广泛支持。 (注意:我不确定 Free BSD 是否支持它 - 因此 ? 指示符)。

    因此,虽然我建议的解决方案确实使用了 mktemp,但您可能希望改用 mkdir -p,因为它得到广泛支持,如下面的 table:

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ IBM │ Open │ Free │ Net │ Darwin/MacOS │ Linux │ Sun     │
                  │ AIX │ BSD  │ BSD  │ BSD │     BSD      │  GNU  │ Solaris │
    ┌─────────────┼─────┼──────┼──────┼─────┼──────────────┼───────┼─────────┤
    │  mkdir -p   │  √  │  √   │  √   │  √  │      √       │   √   │    √    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    

参考资料

以下参考资料用于总结建议的解决方案,并编译兼容性 tables:

  1. tar

  2. mktemp -d -t

  3. rm -rf

  4. mkdir -p

  5. 其他