xargs与exec

一、一个面试题引发的思考

今天去同学公司的时候,和他们人事聊了聊,看到了桌子上的面试题,有一道题很有意思,一共有三份试题,来了三个人面试,两个人写错了,其中一个没回答上来,我也是无语了,就这水平,还出来面试,听人事说口气还大的很,不知道从哪里来的自信?不知道他们是昨学的?

面试题是这样:

请找出/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     #有道云笔记版本

猜你喜欢

转载自www.cnblogs.com/yizhangheka/p/11701213.html