untar a directory of *.tgz files using a wildcard

6,762

Solution 1

You could always do:

ls *.tgz | grep -v Broad_hapmap3_r2_Affy6_cels_excluded.tgz | xargs -n1 tar zxvf

But I suspect somone will post a cleaner way do do this directly from the bash shell without needing a grep in there.

Solution 2

In zsh:

setopt extended_glob
for z in *.tgz~Broad_hapmap3_r2_Affy6_cels_excluded.tgz; do tar xzf $z; done

Another possibility in zsh:

setopt extended_glob
zargs -n 1 -- *.tgz~Broad_hapmap3_r2_Affy6_cels_excluded.tgz -- tar xzf

In ksh (but not bash or zsh as they don't support and patterns):

for z in @(*.tgz&!(Broad_hapmap3_r2_Affy6_cels_excluded.tgz); do tar xzf "$z"; done

Another way in ksh:

( FIGNORE=Broad_hapmap3_r2_Affy6_cels_excluded.tgz;
  for z in *.tgz; do tar xzf "$z"; done )

In bash:

( GLOB_IGNORE=Broad_hapmap3_r2_Affy6_cels_excluded.tgz;
  for z in *.tgz; do tar xzf "$z"; done )

In any shell:

for z in *.tgz; do
  [ "$z" = Broad_hapmap3_r2_Affy6_cels_excluded.tgz ] || tar xzf "$z"
done

Yet another hackish way:

mv Broad_hapmap3_r2_Affy6_cels_excluded.tgz Broad_hapmap3_r2_Affy6_cels_excluded.tgz.not
for z in *.tgz; do tar xzf "$z"; done
mv Broad_hapmap3_r2_Affy6_cels_excluded.tgz.not Broad_hapmap3_r2_Affy6_cels_excluded.tgz

If you also want to act on files in subdirectories, find is the natural tool to turn to. The recursive examples below exclude files named Broad_hapmap3_r2_Affy6_cels_excluded.tgz in any subdirectory.

find . -name '*.tgz' -type f \
       \! -name Broad_hapmap3_r2_Affy6_cels_excluded.tgz \
       -exec tar xzf {} \;

For a recursive traversal in zsh or bash ≥4, you can use ** in patterns. In zsh:

setopt extended_glob
zargs -n 1 -- **/*.tgz~**/Broad_hapmap3_r2_Affy6_cels_excluded.tgz -- tar xzf

In bash ≥4:

shopt -s globstar
( GLOB_IGNORE=Broad_hapmap3_r2_Affy6_cels_excluded.tgz;
  for z in **/*.tgz; do tar xzf "$z"; done )

You can even use find if you don't want a recursive traversal, though it's not the most convenient way then.

find *.tgz  -type f \
            \! -name Broad_hapmap3_r2_Affy6_cels_excluded.tgz \
            -exec tar xzf {} \;

Solution 3

For one-off things like this, I'd just brute-force it:

for f in *.tgz; do 
   [[ "$f" != "Broad_hapmap3_r2_Affy6_cels_excluded.tgz" ]] && tar zxvf "$f"
done
Share:
6,762

Related videos on Youtube

Alen Milakovic
Author by

Alen Milakovic

Updated on September 17, 2022

Comments

  • Alen Milakovic
    Alen Milakovic over 1 year

    I've got a directory that looks like

    $ ls
    Broad_hapmap3_r2_Affy6_cels_excluded.tgz  DINGO.tgz                     GIGAS.tgz  index.html          IONIC.tgz             passing_cels_sample_map.txt  SCALE.tgz
    CHEAP.tgz                                 EPODE.tgz                     HOMOS.tgz  index.html?C=M;O=A  LOVED.tgz             PICUL.tgz                    SHELF.tgz
    CORER.tgz                                 excluded_cels_md5.txt         HUFFS.tgz  index.html?C=N;O=D  NIGHS.tgz             POSIT.tgz                    SLOTH.tgz
    CUPID.tgz                                 excluded_cels_sample_map.txt  HUSKS.tgz  index.html?C=S;O=A  passing_cels_md5.txt  SAKES.tgz                    TESLA.tgz
    

    I want to unzip all the files that match the extension *.tgz with a single command, except Broad_hapmap3_r2_Affy6_cels_excluded.tgz.

    I can do

    ls *.tgz | xargs -n1 tar zxvf
    

    for all the *tgz files, but what's a good way to exclude a subset of them? From reading online maybe find is indicated in this situation, but it seems like overkill. Thank in advance.

    Addendum: I'd also be interested in alternative methods to the question without excluding files.

    • Admin
      Admin about 13 years
      Thanks to everyone for their answers. I'm sorry that I can only accept one. :-)
  • Steven D
    Steven D about 13 years
    In general, you want to avoid parsing the output of ls when possible.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Steven: Sorry, don't follow. Can you elaborate?
  • Steven D
    Steven D about 13 years
    When you parse the output of ls you can run into a lot of problems if you encounter filenames with special characters. See the following for a better explanation: mywiki.wooledge.org/ParsingLs
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Steven: Thanks for the link. The referenced article mentions newlines, but now that I think about it, in Windows world for example, they like filenames with spaces in them, and try to export it elsewhere, and that would by itself mess up the oneliner here, I think. What would you prefer as an alternative? find?
  • Steven D
    Steven D about 13 years
    I would use find for certain complicated cases and glenn jackman's answer in most easy cases. I wouldn't be surprised if there was some magical shell globbing incantation possible with ZSH or Bash 4.
  • Steven D
    Steven D about 13 years
    I think you may have reversed the order of the filenames in your last example. That, or I'm missing something obvious.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Steven: Thank you for your informative comments.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Gilles: Thanks, that's quite a variety of approaches! But you forgot to include an approach using find. :-)
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 13 years
    @Steven: fixed. @Faheem: done.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Gilles: fyi, if you put two @user in the same comment, only the first is notified. See item 7 in meta.stackoverflow.com/questions/43019/…
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 13 years
    @Faheem: I've read that. I was counting on your being notified of my edit.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Gilles: Ok. Just trying to be helpful. So, do all your solutions work for arbitary filenames? Ie. do they avoid the problem mentioned by Steven above?
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 13 years
    @Faheem: Above what? Do you mean in If you mean in his comments to bdk's answer, the problems are due to the use of ls. All the commands in my answer work with arbitrary file names. Be sure to use double quotes everywhere I've used them. If you generalize to commands other than tar, you'll need to add -- before "$z" or {} in some places, but here the file name is an argument to tar's -f option, not directly to the tar command, so you don't need and cannot use --.
  • Alen Milakovic
    Alen Milakovic about 13 years
    @Gilles: yes, I meant in Steven's comments in bdk's answer. Thanks.