由于 tar 命令最初是设计用于读取和写入磁带设备(tar - Tape ARchiver),因此您只能指定要放入存档中的文件名(写入磁带)或要从存档中提取的文件名(从磁带读取)。
有一个选项可以告诉 tar,存档不在某些磁带上,而是在文件中:-f。此选项需要一个参数:包含存档的文件的文件名。所有其他(后续)文件名都被视为存档成员,如下所示:
tar -x -f backup.tar myfile.txt
# 或者(在我看来更常用的语法)
tar xf backup.tar myfile.txt
现在,这里有一个常见的错误——假设有一个包含以下你想要一次性提取的存档文件的目录:
$ ls
backup1.tar backup2.tar backup3.tar
你可能会想到使用tar xf *.tar命令。让我们看看
$ tar xf *.tar
tar: backup2.tar: 在存档中找不到
tar: backup3.tar: 在存档中找不到
tar: 存档中的前一个错误退出
这是因为 shell 用匹配的文件名替换了 *.tar,实际上变成了:
tar xf backup1.tar backup2.tar backup3.tar
这意味着“从存档 backup1.tar 中提取文件 backup2.tar 和 backup3.tar”,当然只有在存档中存储这些文件名时才会成功。
解决方法相对简单:逐个提取所有存档的内容。由于我们使用的是 Unix shell,而且我们很懒,因此我们使用循环来完成:
for tarname in ./*.tar; do
tar xf "$tarname"
done
这个 for 循环将遍历所有与 *.tar 匹配的文件名,并为每个文件名调用 tar xf。这样,您就可以逐个提取所有存档,而且还可以自动完成。
现在,这些天中的第二种常见存档类型是 ZIP。从 ZIP 文件中提取内容的命令是 unzip(谁会想到呢!)。这里的问题是完全相同的:unzip 只接受一个选项来指定 ZIP 文件。因此,您可以以完全相同的方式解决它:
for zipfile in ./*.zip; do
unzip "$zipfile"
done
如果您需要解压缩多个符合某个模式的 ZIP 文件,可以使用 unzip 的 -p 选项,指定 shell-like patterns 来指定 ZIP 文件名。为了避免 shell 解释这些模式,您需要对它们进行引用。在这种情况下,unzip 本身而不是 shell 将解释 *.zip:
unzip "*.zip"
# 或者,为了更清楚地说明我们在做什么:
unzip \*.zip
unzip 的这个特性主要源于它作为一个 MS-DOS 程序的起源。MS-DOS 的命令解释器不执行通配符扩展,因此每个 MS-DOS 程序必须能够将通配符扩展为文件名列表。这个特性留在了 Unix 版本中,正如我们刚刚演示的,它偶尔会很有用。
了解更多shell实用技巧,快速掌握大厂一线经验如果您觉得文章内容对你有一点帮助可以关注我,我在头条平台会持续分享更多实用的shell技巧和最佳实践,如果想系统的快速学习shell的各种高阶用法和生产环境避坑指南可以看看《shell脚本编程最佳实践》专栏,专栏里有更多的实用小技巧和脚本代码分享。