您如何一次解压缩多个文件?


72

tar的目录中有一堆文件,我想一次从它们中提取所有文件。但这似乎无济于事:

$ tar xf *.tar

这里发生了什么?如何一次解压缩一堆文件?

Answers:


142

这里发生了什么?

最初,该tar命令旨在用于磁带设备。由于一次只tar在一个设备上执行才有意义,因此该语法被设计为假定一个和仅一个设备。假定传递的第一个文件或目录是保存有问题的归档的设备,以及该归档中要包含在操作中的任何其他文件或目录。因此,对于tar提取(该x选项),传递的第一个文件将是存档,而所有其他文件将是要提取的文件。因此,如果有两个*.tar文件(saya.tarb.tar),您的命令将扩展为:

$ tar xf a.tar b.tar

除非a.tar包含一个名为的文件b.tar,否则该tar命令将不执行任何操作并安静地退出。令人讨厌的是,Solaris版本的tar既没有在返回代码中也没有在详细选项(v)上报告任何问题。同时,即使关闭了verbose选项,也GNU tar将返回2和发送垃圾邮件STDERR

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

如何一次解压缩一堆文件?

现在重写为时已晚,tar不能接受多个存档文件作为输入,但是要克服该限制并不是很困难。

对于大多数人而言,tar多次运行多个归档文件是最方便的选择。仅传递一个文件名即可tar xf提取所有已存档的文件。一种方法是使用shellfor循环:

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

另一种方法是使用xargs

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

或者,您可以使用多种备用tar文件阅读器之一。最后,真正敬业的程序员可以轻松编写出tar完全符合要求的替代程序。该格式很简单,许多编程语言都有可用于读取tar文件的库。例如,如果您是Perl程序员,请看一下该Archive::Tar模块。

一个警告

盲目解开一堆文件可能会导致意外问题。最明显的是,一个特定的文件名可能包含在多个tar文件中。由于tar默认情况下会覆盖文件,因此最终使用的文件的确切版本将取决于归档的处理顺序。更麻烦的是,如果尝试这种“聪明”的优化,您可能最终会损坏文件副本:

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

如果两个a.tarb.tar包含相同的文件,并试图在同一时间提取出来,结果是不可预知的。

一个相关的问题,尤其是从不受信任的来源获取档案时,可能会发生炸弹

一种部分解决方案是自动创建一个新目录以提取到:

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.


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

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 Ericson

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

Great explanation!
information_interchange

11

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.


7
find . -maxdepth 1 -name '*.tar' -exec tar -xf '{}' \;

7
An explanation of what the code does would be useful!
DNKROZ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.