53

I was wondering whether (and, of course, how) it’s possible to tell tar to extract multiple files in a single run.

I’m an experienced Unix user for several years and of course I know that you can use for or find or things like that to call tar once for each archive you want to extract, but I couldn’t come up with a working command line that caused my tar to extract two .tar.gz files at once. (And no, there’s nothing wrong with for, I’m merely asking whether it’s possible to do without.)

I’m asking this question rather out of curiosity, maybe

  • there’s a strange fork of tar somewhere that supports this
  • someone knows how to use the -M parameter that tar suggested to me when I tried tar -zxv -f a.tgz -f b.tgz
  • we’re all blind and it’s totally easy to do — but I couldn’t find any hint in the web that didn’t utilize for or find or xargs or the like.

Please don’t reply with tar -zxvf *.tar.gz (because that does not work) and only reply with “doesn’t work” if you’re absolutely sure about it (and maybe have a good explanation why, too).

Edit: I was pointed to an answer to this question on Stack Overflow which says in great detail that it’s not possible without breaking current tar syntax, but I don’t think that’s true. Using tar -zxv -f a.tgz -f b.tgz or tar -zxv --all-args-are-archives *.tar.gz would break no existing syntax, imho.

3
  • Out of curiosity, what is the situation that caused you to start thinking about how to avoid a looping construct?
    – unclejamil
    Sep 1, 2011 at 2:35
  • 1
    FYI: GNU tar supports multi-volume tar archives with the -M parameter.
    – Steve-o
    Sep 1, 2011 at 2:49
  • 1
    unclejamil: I’m writing a HowTo and one of the steps in it involves unpacking several compressed files (.tar.bz2, .tar.gz, .zip). And since it’s a HowTo, I was wondering what the most elegant command line to do that would be. :)
    – scy
    Sep 1, 2011 at 9:45

3 Answers 3

58

This is possible, the syntax is pretty easy:

$ cat *.tar | tar -xvf - -i

The -i option ignores the EOF at the end of the tar archives, from the man page:

-i, --ignore-zeros
ignore blocks of zeros in archive (normally mean EOF)
7
  • 3
    This seemed to work for me. Exact command I used was: cat *.tar.bz2 | tar -ixjv. Thanks!
    – scy
    Sep 1, 2011 at 9:40
  • 2
    <For tgz> cat *.tgz | tar -xzvf - -i -C /destination/ <or> for file in *.tgz; do tar -xzvf $file -C /destination/; done
    – Ferroao
    Dec 6, 2017 at 13:18
  • @polynomial: is there any reason, why we cant use ls instead of cat? wouldnt that work as well?
    – Hossein
    Feb 2, 2020 at 3:55
  • 2
    @Rika, tar -f - reads from stdin, hence one needs to pipe the content of the archives, not their names. That's why ls wouldn't work.
    – Daniel Le
    Dec 29, 2020 at 8:44
  • @DanielLe Thanks a lot really appreciate it
    – Hossein
    Dec 29, 2020 at 9:23
38

For *.tar.gz:

for file in *.tar.gz; do tar -zxf "$file"; done

For *.tar.bz2:

for file in *.tar.bz2; do tar -jxf "$file"; done

For *.tar.xz:

for file in *.tar.xz; do tar -Jxf "$file"; done

For *.tar.zst new:

for file in *.tar.zst; do tar --zstf -xf "$file"; done
3
  • this is great. the format is also great because thats how it looks in the terminal Apr 10, 2015 at 11:31
  • 1
    Don't forget to put quotes around $file if your files have names with spaces. Dec 1, 2016 at 13:22
  • 3
    This does not really answer the question of whether it's possible to extract multiple archives using a single invocation of tar. Furthermore, the user says they are already familiar with how to use for-loops to iterate over a set of files.
    – Kusalananda
    May 21, 2018 at 12:35
2

You need to use a loop. It wouldn't break the tar command line syntax to allow multiple -f options, but it would require adding code to process several archives in sequence, with all kinds of edge conditions (What happens if an archive in the middle is malformed? Can the archives use different compression mechanisms? Can you have multiple -C options (GNU tar option to extract to a particular directory), too? What about -K (GNU tar option to start at a certain member name)? …).

One possibility avoiding a for loop is to install and activate AVFS, a FUSE filesystem that provides transparent access to archives. Each archive /path/to/archive doubles as a directory ~/.avfs/path/to/archive#. If you want to match the archives with wildcards, there's a hurdle of adding that # to a wildcard match; it can be done in zsh.

mountavfs
cp -p ~/.avfs$PWD/{a,b}.tgz\#/* /destination
cp -p ~/.avfs/path/to/source/*.tgz(e\''REPLY=$REPLY\#'\')/* /destination

Not the answer you're looking for? Browse other questions tagged or ask your own question.