一、一个面试题引发的思考
今天在去同学公司的时候,和他们人事聊了聊,看到了桌子上的面试题,看到一个面试题很有意思,来了三个人面试,两个人写错了,其中一个没回答回来,我也是无语了,就这水平,还出来面试,听人事说口气还大的很,不知道从哪里来的自信?不知道他们是昨学的?
面试题是这样:
请找出/test.dir目录下的文件中以包含test关键字的文件并将其全部删除(注:不少于两种方法)
有两位面试者都是这么写的:
find ./ -name "*test*" -type f | rm –rf
这么写看上去是没错的,但实际的操作肯定不行的,还是太嫩了!
为什么这么操作不行呢?find向外输出的是什么?我们是按照文件名查找的,找到的其实就文件名组成的字符流,你把一个字符流通过管道传送给rm命令,rm自然会正常的执行,但是这个字符流与文件路径没有关系,这样删除的只是find的查看后的结果,所以就无法删除,那么要怎么做才行能删除呢?只要将FIND查找到的字符流转换成路径就行了,这样方法就多了,我们可以通过find自带的exec或者借助xargs命令将字符流转换为真实的路径就行了,我们来尝试一下:
[root@localhost ~]# mkdir test.dir ; cd test.dir [root@localhost test.dir]# touch test_{01..06}.txt [root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt [root@localhost test.dir]# find ./ -name "*test*" -type f | xargs rm -rf [root@localhost test.dir]# ls #空的
再来尝试另一种办法,这种方法是find自带的,效果去上面的都是一样的。
[root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt [root@localhost test.dir]# find . -type f -name "*test*" -exec rm -f {} \; [root@localhost test.dir]# ls
再来一种更加简单粗暴的方法:
[root@localhost test.dir]# rm -rf `find ./ -name "*test*" -type f` [root@localhost test.dir]# ls #空的
我们再来举一个例子体会一下:
[root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt [root@localhost test.dir]# echo testtesttest > test_01.txt [root@localhost test.dir]# echo testtesttest > test_02.txt #除了这两个文件之外都是空的
[root@localhost test.dir]# find -name "*.txt" | rm -rf #我们已经知道,这样肯定是无法删除这些文件的。 [root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt #果不其然 [root@localhost test.dir]# find -name "*.txt" | grep test #这个操作很正常,将文件名里面包含test的文件都过滤出来了 ./test_01.txt
./test_02.txt
./test_03.txt
./test_04.txt
./test_05.txt
./test_06.txt
[root@localhost test.dir]# find -name "*.txt" | xargs grep test
./test_01.txt:testtesttest
./test_02.txt:testtesttest
#重要的是这里,加一个xargs,grep就不是在文件名里面找了,而是找文件里面找了!!!
仔细体会一下,体会到了吗?好了,我来总结一下吧!
如果没有xargs的话,grep只会把find的结果当做是字符流,并不是将其当做是文件,当有了xargs之后,这些字符流就变成了真正的路径,其实将xargs换成find自带的exec也是可以的,如下所示:
[root@localhost test.dir]# find -name "*.txt" -exec grep test {} \; #{}就是指前面find的结果,标准输出嘛! testtesttest testtesttest
二、再来举两个相似的例子
题目1:
请找出/test.dir目录下的文件中以包含test关键字的文件并将其全部移动到/tmp目录(注:不少于两种方法)
如何操作呢?
第一种方式:
[root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt [root@localhost test.dir]# mv `find -name "*test*" -type f` /tmp #将命令放置到``当中,自动就能将流转换成有意义的路径
第二种方式:
[root@localhost test.dir]# ls test_01.txt test_02.txt test_03.txt test_04.txt test_05.txt test_06.txt [root@localhost test.dir]# find -name "*test*" -type f -exec mv <----写到这里就写不下去了!
#mv的语法是这样的:mv <被移动的文件> <目标文件夹>,但是这里find会将结果补全到最后也就是<目标文件夹>的位置,怎么办?
#exec是不能用了,我们可以这样,如下所示:
[root@localhost test.dir]# find -name "*test*" -type f | xargs mv -t /tmp
#xargs我们已经理解了,那-t是什么意思?mv -t的意思就是将<被移动的文件>和<目标文件夹>换一下位置,这样find的结果就正好补全到<被移动的文件>,这不就完美了!
第三种方式:
第三种方式与第二种方式差不多,不过我们不用mv的-t选项了,而使用xargs自带的机制了,如下所示:
[root@localhost test.dir]# find -name "*test*" -type f | xargs -i mv {} /tmp;
#这次我们没有改变mv的语法,只是用中括号代替了<被移动的文件>,不要xargs前面要加一个-i的选项,只有这样中括号才有意义!
题目2:
请找出/test.dir目录下的文件中以包含test关键字的文件并将其全部复制到/tmp目录(注:不少于两种方法)
如何操作呢?
[root@localhost test.dir]# find ./ -name "*test*" -type f | xargs -i cp {} /tmp; [root@localhost test.dir]# find ./ -name "*test*" -type f | xargs cp -t /tmp; [root@localhost test.dir]# cp `find ./ -name "*test*" -type f` /tmp
我打字累了,不解释了,第一个题目看懂后,这一个题目看懂自然不成问题!!!
现在,我真想大声对那三个面试者说:
哈哈!
文档:exec与xargs.note
链接:http://note.youdao.com/noteshare?id=02401541ecae82d3fb7f3093fca2d6c2&sub=C82F67ED974C49C0AED08685729E975F #有道云笔记版本