62

I have a directory e.g. /var/tmp/my-dir/ that I frequently compress with the following command:

$ cd /var/tmp/
$ tar -zcf my-dir.tar.gz my-dir/*

Later, when I untar my-dir.tar.gz, it'll create my-dir/ in the current directory. It sounds like the my-dir directory is "wrapped" inside the tarball. Is there a tar option to rename my-dir to e.g. your-dir before the actual tarring happens. So that ...

$ tar -zxf my-dir.tar.gz
# So that ... this creates your-dir/, instead of my-dir/

Thanks.

moey
  • 10,587
  • 25
  • 68
  • 112

3 Answers3

91

Which tar?

GNU Tar accepts a --transform argument, to which you give a sed expression to manipulate filenames.

For example, to rename during unpacking:

tar -zxf my-dir.tar.gz --transform s/my-dir/your-dir/

BSD tar and S tar similarly have an -s argument, taking a simple /old/new/ (not a general sed expression).

ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 1
    @ephemient, I had to use --transform='pattern', like: sudo tar -xjvf thunderbird-14.0.tar.bz2 --transform='s/thunderbird\(\/\)/thunderbird.14\1/' with ln -sf thunderbird.14 thunderbird, update thunderbird won't be a problem! \m/ – Rodrigo Gurgel Jul 23 '12 at 20:08
  • 1
    `--transform` introduced in 1.2, unfortunately RHEL and CentOS 5.10 only comes with tar v1.15 :( – Aaron R. Jun 23 '14 at 18:28
  • BSD tar does not seem to have --transform option, so on MacOS not sure if this works darn – Alexander Mills May 15 '18 at 19:38
  • 1
    This answer will not work correctly. It will break all symlinks inside the directory that have a target that contains the string `my-dir`. – Alistair Buxton Oct 21 '19 at 15:15
18

For mac works -s flag.

Rename on compress:

tar -zcf my-dir.tar.gz -s /^my-dir/your-dir/ my-dir/*

Rename on extract:

tar -zxf my-dir.tar.gz -s /^my-dir/your-dir/

DamneD
  • 217
  • 2
  • 5
  • nice, thanks! I need this answer because I am on MacOS ( I think it uses BSD tar, not GNU tar) – Alexander Mills May 15 '18 at 19:39
  • Anyone know how to escape chars in the sed string? I tried backslashes (with and without quoting) -- but always get an error from tar. In particular I want to transform `.svn/patches` to `__patches`, e.g. `-s /^\.svn\/patches/__patches/`. I note that `-s /^.svn.patches/__patches/` works but I would rather be more explicit. – user9645 Jan 09 '19 at 12:00
  • I got an answer [here](https://stackoverflow.com/a/54110456/1571426) - apparently tar has an issue when escaping the delimiting character, so the answer is to use a different delimiter. – user9645 Jan 09 '19 at 13:57
  • MacOS has it's own proprietary tar options? Yuck. – Cerin Aug 27 '19 at 01:14
  • This answer is slightly better, but it can still break symlinks that start with the string `my-dir`. This is because symlinks can be relative, and the `my-dir` it refers to may not be at the top level of the tar file. – Alistair Buxton Oct 21 '19 at 15:18
  • P.S. don't use `/` as your expression separator - since you'll be passing in directory paths. Better to use an obscure character like `!` e.g. `-s !^my-dir!your-dir!`. That way `my-dir` or `your-dir` can contain sub-directories and not cause a parsing error. – colm.anseo May 20 '20 at 03:22
  • Unfortunately, this does not work with the built-in BSD tar on Windows 10. `-s` does not exist with that distribution. – kakyo Oct 02 '21 at 05:52
13

Late to to the party but here's my time-proven approach to this. When I have a tar file that extracts to a top level directory name I don't like, I solve it by creating the directory name I do like and then using tar with the -C and --strip-component options.

mkdir your-dir && tar -zxvf my-dir.tar.gz -C your-dir --strip-components=1

The -C extracts as if in the directory you specify while the --strip-component says to ignore the first level stored in the tarfile's contents.

At first glance this approach is perhaps less elegant than the sed-style solution given by others, but I think this way does have some merit.

SO Stinks
  • 3,258
  • 4
  • 32
  • 37
  • Works great on Ubuntu 20 ! – Binita Bharati Jul 19 '21 at 11:03
  • This is a better solution, when you don't know the root directory name. For example, when need to build `ImageMagick`, you can download sources, which contains versioned root directory name. When need to automate this, you can't use other approaches, if you don't know the actual version of sources. Sure, it can be achieved, but much easier to use this answer. – yaroslavche Jan 06 '22 at 11:39