Alexander Mills
Alexander Mills

Reputation: 100010

Cross-platform way to remove dir from tarball

I found this: https://www.cyberciti.biz/faq/unix-linux-appleosx-bsd-tar-remove-directory/

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

but this does not work on MacOS. I get:

tar: Option --delete is not supported

I am looking for something that works on all *nix flavors. Anybody know a good way to do this? Maybe I really do need to extract first and ignore the folder and then re-tarball it?

Upvotes: 2

Views: 850

Answers (1)

RobC
RobC

Reputation: 24992

Short Answer

Yes, if you want a solution that works on many *nix flavours then you're going to have to; extract first, ignore the folder, and then re-tarball it.


Solution:

I would do something like the following:

# 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"

Why do I recommend the solution shown above:

Firstly, (for hopefully obvious reasons) it's beyond my capacity to be able to test and confirm that the solution above works successfully across all *nix flavours. Secondly, it would be naive of me to say otherwise because, (as I'm sure you're aware), it's a big old landscape out there, i.e. there's many versions, flavours, and variants.

I have concluded upon the solution suggested above based on the following findings/research. The flavours of *nix covered in the support/compatibility tables below are far from exhaustive. I've selected them from the flavours listed here.

A majority of the chosen flavours are those that are developed by groups of volunteers who make them available for free (Open BSD, Free BSD, etc). Fortunately documentation, man-pages, etc for these *nix flavours are published online and they have been the main influence in my decision making. IBM AIX, and Sun's Solaris being the exceptions as they're proprietary, however some docs, man-pages, etc were available for those two.


Support/Compatibility Tables

  • The tar --delete option

    Let's begin by looking at support for the tar commands --delete option. As you can see in the table below, it's far from widely supported :( Hence why it seems necessary to take the more verbose solution - unfortunately we can't utilize a oneliner when cross-platform is a requirement.

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

    The solution provided above utilizes several of the tar options, namely; -z, -x, -f, -c, and -C. As you can see in the table below they are widely supported. However, notably the -z option, (which is used to filter the archive through gzip), is not supported on IBM's AIX which to my understanding is used on mainframes - (so, my assumption is that's probably not to much of a dealbreaker for you).

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ 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    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    

    The tar --exclude option

    Note in the previous table the --exclude option doesn't appear to be widely supported too - for this reason we don't use it in the suggested solution. I would avoid opting to exclude the unwanted directory (i.e. the one you want to delete) when unpacking the .tar. So avoid doing something like this:

    # 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"
    

    You'll notice in the suggested solution we unpack all the contents (without exclusion), then remove the unwanted directory using rm -rf, before repacking it.


  • Other commands the solution utilizes

    The table below shows the remaining commands utilized in the suggested solution:

                  ┌─────┬──────┬──────┬─────┬──────────────┬───────┬─────────┐
                  │ 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  │  √   │  ?   │  √  │      √       │   √   │    √    │
    └─────────────┴─────┴──────┴──────┴─────┴──────────────┴───────┴─────────┘
    

    As you can see, we're good to utilize rm -rf as it's well supported.

    Be cautious of mktemp...

    mktemp and it's -t and -d option seems to be less widely supported. (Note: I'm unsure whether it is or isn't supported on Free BSD - hence the ? indicator).

    So, whilst my suggested solution does utilize mktemp, you may want to use mkdir -p instead, as that's widely supported as shown in the following table:

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

References

The following references were used to conclude on the suggested solution, and compile the compatibility tables:

  1. tar

  2. mktemp -d -t

  3. rm -rf

  4. mkdir -p

  5. Others

Upvotes: 5

Related Questions