直接看示例:
root@listen:/web/test # mkdir -p aa/bb/cc/dd/ee
root@listen:/web/test # touch aa/bb/cc/dd/ee/ff.txt
root@listen:/web/test # tar -cvf test.tar ./*
a ./aa
a ./aa/bb
a ./aa/bb/cc
a ./aa/bb/cc/dd
a ./aa/bb/cc/dd/ee
a ./aa/bb/cc/dd/ee/ff.txt
root@listen:/web/test #
说明:新建一个多层目录aa/bb/cc/dd/ee,然后在里面建一个新文件ff.txt。完成后再对这个目录进行tar打包。
现在的目的是:怎么样只解压出ff.txt,并且存放到当前目录?
为了防止混淆,我们转一个目录,然后把刚才创建的test.tar复制进来:
root@listen:/web/test1 # pwd
/web/test1
root@listen:/web/test1 # ls
test.tar
先来解压看一下,这样得到的路径跟test里面一模一样,然后再删除掉,以便做试验:
root@listen:/web/test1 # tar -xvf test.tar
x ./aa/
x ./aa/bb/
x ./aa/bb/cc/
x ./aa/bb/cc/dd/
x ./aa/bb/cc/dd/ee/
x ./aa/bb/cc/dd/ee/ff.txt
root@listen:/web/test1 # ls
aa test.tar
root@listen:/web/test1 # ls aa
bb
root@listen:/web/test1 # ls bb
ls: bb: No such file or directory
root@listen:/web/test1 # ls aa/bb/cc/dd/ee/ff.txt
aa/bb/cc/dd/ee/ff.txt
root@listen:/web/test1 # rm -rf aa/
tar除了可以指定tar文件外,还可以有第二个参数,表示“仅解压符合条件的文件”,但是这个参数是一个“pattern”,即“模式”,也就是相当于“正则”,所以注意下面两条命令的区别,特别注意第二条命令,由于前面有个星号(*),所以要加上引号才能正确执行,否则会被shell解释为“通配符”:
root@listen:/web/test1 # tar -xvf test.tar "ff.txt"
tar: ff.txt: Not found in archive
tar: Error exit delayed from previous errors.
root@listen:/web/test1 # tar -xvf test.tar "*/ff.txt"
x ./aa/bb/cc/dd/ee/ff.txt
root@listen:/web/test1 # ls
aa test.tar
上面的结果显示,这种解压虽然也只解压了指定的文件,但是并没有把多层路径去除,现在我们的目的是:把ff.txt解压到当前/web/test1下面,而不是/web/test1/aa/bb/cc/dd/ee/ff.txt。
tar还提供了一个“替换”模式,这是Linux的gtar没有的功能(也许有,但是百度到的那些的谓的详解里都没找到),就是用-s参数,man里面很长,找最有用的一段:
-s pattern
Modify file or archive member names according to pattern. The
pattern has the format /old/new/[ghHprRsS] where old is a basic
regular expression, new is the replacement string of the matched
part, and the optional trailing letters modify how the replace-
ment is handled. If old is not matched, the pattern is skipped.
摘取重点说,就是模式替换的格式为“/旧名/新名/选项”,旧名新名都支持通配符,至于shell的通配符,在这儿就不展开讲,详细内容可以参照shell的文档。
那我们来规划一个pattern,要把”./bb/cc/dd/’等去掉,old应该为:./.*/,但是放到pattern中就了问题了,因为本身就有斜杠“/”,再写作“/./.*///g”,这种写法是不允许的。
可能你想到了转义,我们来试一下:
root@listen:/web/test1 # tar -xvf test.tar -s "/.\/.*\///g" "*/ff.txt"
tar: Invalid regular expression: trailing backslash (\)
得到了tar的抱怨:不正确的正则表达式:反斜杠错误!
原来反斜杠“\”在pattern中也有其他的含义,所以这路走不通了。
顺便说一下,上面用的规则:第一块old部分已经了解,第二块new部分是一个空串,实际效果就是删除掉,在这块中可以用\1,\2来代表前面小括号内的部分,这跟正则一样。同时,你也看到反斜杠的用途了。
那怎么办呢?
bsd里还有个不成文的规定:模式的分界符还可以用其他字符代替,我们可以用冒号来代替斜杠“/”
root@listen:/web/test1 # tar -xvf test.tar -s ":./.*/::g" "*/ff.txt"
x ff.txt
root@listen:/web/test1 # ls
aa ff.txt test.tar
怎么样?解压出单独文件ff.txt了吧!
还可以换成其他的分界符:
root@listen:/web/test1 # tar -xvf test.tar -s ",./.*/,,g" "*/ff.txt"
x ff.txt
root@listen:/web/test1 # tar -xvf test.tar -s ">./.*/>>g" "*/ff.txt"
x ff.txt
root@listen:/web/test1 # tar -xvf test.tar -s "@./.*/@@g" "*/ff.txt"
x ff.txt
root@listen:/web/test1 # tar -xvf test.tar -s "|./.*/||g" "*/ff.txt"
x ff.txt
有时是需要临时发挥的。
这样做有什么实际用处呢?比如我有一个系统的打包备份,有上万个文件,一天误删除了一个文件,想从这个包里面取出一个文件,如果都解开比较麻烦,而这个的路径又比较深,找起来挺麻烦,就可以利用这个命令把这个文件方便地取出来。