85

I have a bunch of tar files in a directory and I want to extract all the files from them at once. But this doesn't seem to do anything:

$ tar xf *.tar

What's going on here? How do I untar a bunch of files at once?

Steve Rowe
  • 19,411
  • 9
  • 51
  • 82
Jon 'links in bio' Ericson
  • 20,880
  • 12
  • 98
  • 148

3 Answers3

159

What's going on here?

Originally, the tar command was intended for use with magnetic tape devices. Since it only made sense to execute tar on one device at a time, the syntax was designed to assume one and only one device. The first file or directory passed was assumed to be the device that held the archive in question and any other files or directories where the contents of the archive to be included in the operation. So for tar extraction (the x option), the first file passed would be the archive and all other files would be the files to be extracted. So if there are two *.tar files (say a.tar and b.tar) your command would expand to:

$ tar xf a.tar b.tar

Unless a.tar contains a file named b.tar, the tar command has nothing to do and exits quietly. Annoyingly, the Solaris version of tar does not report any problems either in the return code or with the verbose option (v). Meanwhile, GNU tar returns 2 and spams STDERR even with the verbose option off:

tar: b.tar: Not found in archive
tar: Exiting with failure status due to previous errors

How do I untar a bunch of files at once?

It's too late rewrite tar to accept multiple archive files as input, but it's not too hard to work around the limitation.

For most people, running tar multiple times for multiple archives is the most expedient option. Passing just one filename to tar xf will extract all the archived files as one would expect. One approach is to use a shell for loop:

$ for f in *.tar; do tar xf "$f"; done

Another method is to use xargs:

$ ls *.tar | xargs -i tar xf {}

Alternatively, you can use one of a number of alternative tar file readers. Finally, the truly dedicated programmer could easily write an tar replacement that works exactly as desired. The format is straightforward and many programming languages have libraries available to read tar files. If you are a Perl programmer, for instance, take a look at the Archive::Tar module.

A warning

Blindly untarring a bunch of files can cause unexpected problems. The most obvious is that a particular file name may be included in more than one tar file. Since tar overwrites files by default, the exact version of the file you end up with will depend on the order the archives are processed. More troubling, you may end up with a corrupted copy of the file if you try this "clever" optimization:

for f in *.tar; do
  tar xf "$f" &
done
wait

If both a.tar and b.tar contain the same file and try to extract it at the same time, the results are unpredictable.

A related issue, especially when taking archives from an untrusted source, is the possibility of a tarbomb.

One partial solution would be to automatically create a new directory to extract into:

for f in *.tar; do 
  d=`basename "$f" .tar`
  mkdir "$d"
  (cd "$d" && tar xf "../$f")
done

This won't help if a file is specified in the archive with an absolute path (which is normally a sign of malicious intent). Adding that sort of check is left as an exercise for the reader.

djoffe
  • 102
  • 8
Jon 'links in bio' Ericson
  • 20,880
  • 12
  • 98
  • 148
  • 1
    My tar man page says "The -l and -i options appear in the 1997 version of the POSIX standard, but do not appear in the 2004 version of the standard. Therefore you should use -L and -I instead, respectively." For this task, I'd be careful with xargs and use "-n1" to avoid the original problem. – slacy Feb 24 '09 at 22:31
  • 1
    @slacy: I think you mean the GNU xargs manpage. I suppose you are right, but I really don't like the way that would turn out: "xargs -I {} tar xf {}". On the other hand, "-n1" works fine in this case: "| xargs -n1 tar tf". It's even an improvement. But that's a new trick to this old dog. ;-) – Jon 'links in bio' Ericson Feb 24 '09 at 22:57
  • 1
    Great answer, but I'd like to add that if one of the tars includes a whitespace this will fail, unless we wrap quotes around the tar parameter: `for f in *.tar; do tar xf "$f"; done` – Enoon Mar 09 '16 at 10:02
16

If all the tar files are in the same folder, then I do this in tcsh shell. Works all the time.

find -iname \*.tar -exec tar -xvf {} \;

This is same as the above answer, a little bit more concise I think.

Snehashis Roy
  • 161
  • 1
  • 3
9
find . -maxdepth 1 -name '*.tar' -exec tar -xf '{}' \;
Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
user3734617
  • 99
  • 1
  • 1