3

If I have a .tar or .tgz or .tbz on my desktop, and I double click on it, I get the folder that was compressed, neatly decompressed right next to the archive file. Just like you'd expect.

When I try to decompress a tarred item via the tar command, the output I get has the whole full path of the original compressed file.

So for example, if I make a .tbz out of a folder on my desktop called "foo", and then I decompress it via tar -xf foo.tbz ~/Desktop/foo, what I get is: /Users/[user]/Desktop/foo/Users/[user]/desktop/foo/bar.txt

Is there some magic flag in tar that I'm not seeing? I've googled up 'how-to' after 'how-to' that give you a simple tar command to extract a file, but all the directions I see give me my undesired result with long, unnecessary, super-nested result directors.

  • Which options to tar do you use to pack the file in the first place? What is the output of tar tvzf foo.tbz? – nohillside Mar 20 at 15:15
  • It's not clear exactly what you're asking. Are you attempting to change the directory where your extracted files go (overriding the folder hierarchy) or are you attempting to extract a single file to a particular directory? – Allan Mar 20 at 15:18
  • @Allan I am attempting to unpack the entire archive to a location I specify. Which is half working, but I'm getting the original full path to each file in my custom location. If I use the built in Archive Utility.app to decompress, I don't have this problem (but I'm making a script so that doesn't actually help me). – l008com Mar 20 at 15:21
  • @nohillside I don't recall exactly but probably something like tar -cvjf '/folder.tbz' '/path/to/folder' – l008com Mar 20 at 15:24
  • 1
    If you specify the full path when packing the file, the full path will be used to extract. – nohillside Mar 20 at 15:34
1

The option you are looking for is --strip-components (from man tar):

--strip-components count

(x mode only) Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped.

But it is not 100% equivalent to the way the Finder works: you still need to know the directory depth to strip.

Fortunately, it can be calculated with this command:

while read; do echo -n "$REPLY" | wc -c; done < <(tar tvf <tar archive name> | egrep -v '^d' | sed 's:[^/]::g') | sort -n | uniq | head -n 1

Since you have to replace <tar archive name> with the name of your tar archive, it is not as convenient as simply double clicking it in the Finder, but it can be useful in Bash scripts.

If the tar archive contains several files in different paths, the command above calculates the maximum common directory depth:

tar archive contents          =>      extracted files using --strip-components

dir1/dir2/file1               =>      file1
dir1/dir2/dir3/file2          =>      dir3/file2
dir1/dir2/dir3/dir4/file3     =>      dir3/dir4/file3

For example, if you create a tar file like this:

mkdir -p a/b/c/d/e/f
touch a/b/c/d/e/f/myfile1
touch a/b/c/d/e/myfile2
tar cvf file.tar a

so that:

tar tf file.tar
a/
a/b/
a/b/c/
a/b/c/d/
a/b/c/d/e/
a/b/c/d/e/f/
a/b/c/d/e/myfile1
a/b/c/d/e/f/myfile2

you can extract all files (with the shortest directory depth) as follows:

  1. Calculate maximum common directory depth:

    while read; do echo -n "$REPLY" | wc -c; done < <(tar tvf file.tar | egrep -v '^d' | sed 's:[^/]::g') | sort -n | uniq | head -n 1
    

    Command returns 5.

  2. Run tar passing the result of the previous command to --strip-components:

    tar xvf file.tar --strip-components 5
    x f/
    x myfile1
    x f/myfile2
    

Instead of running two commands, you can use $() to pass the result directly to --strip-components:

tar xvf file.tar --strip-components $(while read; do echo -n "$REPLY" | wc -c; done < <(tar tvf file.tar | egrep -v '^d' | sed 's:[^/]::g') | sort -n | uniq | head -n 1)
x f/
x myfile1
x f/myfile2

This command also properly deals with the case of a tar archive without a directory hierarchy:

touch myfile3
tar cvf file2.tar myfile3
tar xvf file2.tar --strip-components $(while read; do echo -n "$REPLY" | wc -c; done < <(tar tvf file2.tar | egrep -v '^d' | sed 's:[^/]::g') | sort -n | uniq | head -n 1)
x myfile3

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .