遭遇rm与管道问题:
一 问题初始:
用通常意义的管道使用这样可以:
(1)ls -l | sed -n '/~$/p' 我用显示出系统自己建立的备份文件
这时,我想删除这些文件,我仍然使用了管道,并执行了以下命令
(2)ls -l | sed -n '/~$/p' | rm -rf
然后又用(1)中的命令显示,结果完全未变,即未删除任何文件
上互联网上查解,应如下使用:
ls -l | sed -n '/~$/p' | xargs rm -rf
执行,则结果与预期相同,即删除了所以生成的备份文件
当然此问题还可以这样解:
find . -name '*~' -type f | xargs rm -rf
find . -name '*~' -type f -exec rm {} \;
二 有关I/O重定向
借此机会好好学习一下I/O重定向,这部分的知识总是一知半解的,下面的东西是从网上搜来的东西,自己理解完,整理好了,又加入了自己的一些注解。
Unix系统的I/O重定向是一项非常重要功能。可以利用>大于符号进行输出重定向,也可以利用<进行输入重定向,还有一个|的管道符号,可以将前级命令的输出定向
给下级的命令当输入。基本上,Linux将标准I/O分为三种。分别是标准输入、标准输出以及标准错误输出。标准输入就是标准输入设备键盘的输入,或是一
般Linux命令后面所加的参数。而标准输出一般就是指输出到Terminal或更通俗的说法是屏幕console,最后一个标准错误输出,是当命令执行
错误时,输出的错误信息,就称为标准错误输出。
输出重定向符>
例ls -l > list 正常情况下执行ls -l后,应该会有目录和文件的输出结果到屏幕上,但是经过输出重定向符>后,输出结果会存储到list文件中,而屏幕上则无任何结果。所以当一些命令运行并需要将结果记录下来时,输出重定向会是一项好工具。
附加输出重定向符>>
cat list2 >>list1 如果是两个>>符号,就是将输出重定向结果附加到输出文件的后面
输入重定向符<
cat list
cat < list
上面这2个命令的结果是一样的,但是真正执行的意义确是不同的。Cat
list是list当作cat的标准输入文件,结果会将list的内容显示到屏幕上,但是cat <
list则是cat并无标准输入文件,而是使用输入重定向<将文件list定向给cat当标准输入,最后才显示list的内容。这样的输入重定向对
于可以接受“参数”的命令没有太大用处,但对于设计成不能接受参数的命令就非常有用。
错误输出重定向符&>
ls -l dir1 > file_list
ls -l dir1 &> file_list
错误输出重定向&>与输出重定向>仅差一个&符号,它们之间的差别在于使用输出重定向>时,当目录dir1存在时,
输出当然会记录到file_list中,但假若dir1不存在,则ls命令会显示无法列出目录dir1的错误信息到屏幕上。此时为错误输出,所以正常的重
定向并无任何输出结果,因此file_list会是空文件。而错误输出重定向&>则不管是正常的输出信息还是命令执行错误的错误信息,都记
录到file_list文件中。
管道符|。管道的功能是将程序的输出结果引导为另一个程序的输入。Linux系统中的管道分匿名管道和有名管道,匿名管道就是“|”,比较简单,而有名管道就是先建立一个管道文件,然后使用这个管道文件。。
匿名管道使用例: ls -l /usr |more 一页一页的观看ls的输出结果。
有关有名管道的特性说明:
(1) 对于pipe file,以读打开和以写打开需要成对出现,如果只出现一个,如只以读打开pipe file,而没有以写打开pipe
file,那么该读打开(open)操作会被阻塞,即并没有真正打开pipe file,一直到有以写打开的pipe file。
(2) 写入pipe file的内容会被以先进先出的顺序读出,被读出的内容不会继续存在于pipe file中,即pipe file是一种FIFO队列。所以,ls –l看到的pipe file大小一般是0字节的。
(3) 由于pipe file这种读写操作成对出现及一旦对pipe
file有写入的内容,就马上会被读出,所以它可以保证读写的原子操作,不像fprint函数,fprint函数会出现输出内容交叉的情况,如,如果
4.5个fprint函数就把缓冲区填满了,那么第5个fprint函数的前一半输出到缓冲区的内容会write函数首先写入文件,第5个fprint函
数的后半个内容会等到下一个缓冲区填满(或者强制刷新缓冲区)才到真正输出的文件,而在这两个时间段之间,如果有其它进程对相同的文件进行写操作,那么以
后在该文件中会看到第5个fprint函数的内容之间夹带了其它内容。
(4)不能够被cp, scp复制,可以删除,可以改名。可以用来做不同程序间通讯用。
(5)因为管道的读或者写数据都在不同的线程中。一个管道事实上只是一个记忆的缓冲器,它接受两个不同进程的读写,这两个进程答应它们从前到后的传送数据。记忆缓冲器通常会限制大小;当它满的时候它会阻止写进程,当它空的时候,它回限制读进程。它们的优势就是永远不会把内存使用光也不会需要任何磁盘存储。同时还可以避免单个文件大于2G的限制。
建立方式:mknod pipe_filename p
其中pipe_filename是文件名,p表示建立管道文件。
试验:
先创建命名管道 mknod pipe_file p
试验1
cat abcd >pipe_file
在unix系统中使用cat 命令将abcd文件的内容写入pipe_file,而实际上abcd这个文件不存在。由于unix中对一个command
line会首先执行其中的重定向操作,即>pipe_file,而此时,没有为读而打开该pipe_file,因此,重定向操作打开
pipe_file会被阻塞,因此cat打开abcd的操作并没有执行,因此上述命令不会报错打不到abcd这个文件。
一旦有为读操作打开pipe_file,如cat
pipe_file重定向操作的写打开pipe_file会执行,接下来cat abcd也会被执行,这时会报
cat: cannot open abcd的错误。
试验2
echo "abcdefg" > pipe_file 此时shell不会退出,一直阻塞在这里
再开一个窗口,运行: cat pipe_file 结果会显示 abcdefg
同时上一个窗口的echo命令执行完毕返回命令行。
三 重定向其它有效的而且常用的应用
(1)直接使用yes不必按键确认
yes | rm -i *.txt 当删除文件需要确认时,不用按键就删除文件:
yes n | rm -i *.txt 当 rm -i 确认删除文件的时候,敲入n代表not不删除文件。
(2)这里有个想删除第8个目录的例子
ls -l | grep '^d'|awk '{ print $8 }' | xargs -ti rm -fr {} \;
find -type d -exec rm -rf {} \;
(3)find |tar cf file.tar * #用find找出需要的文件再打包
(4)使用命名管道的简单例子
mknod mypipe p
for((i=0;i<15;i++)) ;do echo $i; sleep 1;done>mypipe &
cat 管道 是一种伪文件. 它存在于内存中, 用于快速I/O操作. 管道的缓冲区采用先进先出机制, 即写管道进程写到缓冲区头部而读管道进程读取管道尾部. 建立管道的命令为”mknod filename p".
(5)启动compress进程, 使之从管道读取数据并输出到磁盘文件.
mknod /tmp/exp_pipe p 建立有名管道文件
compress < /tmp/exp_pipe > export.dmp.Z &
输入输出重定向功能都是相对于程序/软件/命令的,在本例中就是compress。从/tmp/exp_pipe中输入,结果输出到export.dmp.Z中。大于/小于号的出现次序不影响该句话的语义。即指compress > /tmp/exp_pipe < export.dmp.Z,若这样写好处是简洁明了,工具的扩展性比较好,坏处是对系统资源占用较多,不经济。
(6)tar cvf - dir gzip > file.tar.gz
gunzip < file.tar.gz tar -xvf –
当你没有空间存储非压缩版本的时候,上面的例子将答应你存储一个文档的压缩版本。
(7)rm -rf * 当目录中的文件非常多时,会执行速度非常慢,这时你可以考虑使用管道如
ls -l | xargs rm -rf 使用管道传递参数,这样不会因为参数过多,而导致rm停止,如管道的特性所讲先进先出及缓冲区的有限性都使得不必一次性传递所有的参数,不会因为占用太多的内存而影响rm的执行速度
以上是有关管道的,可是为什么非使用xargs来传递参数才能正常使用呢,下面再看一下xargs的使用吧
四 有关xargs
|是向应用程序的标准输入灌输信息
xargs是在应用程序执行时候传入参数
4.1 维基百科上关于xargs的解释,如下:
xargs是一条和的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。
例如,下面的命令:
rm 'find /path -type f'
如果path目录下文件过多就会因为“参数列表过长”而报错无法执行。但改用"xargs"以后,问题即获解决。
find /path -type f -print0 | xargs -0 rm
本例中"xargs"将产生的长串文件列表拆散成多个子串,然后对每个子串调用"rm"。这样要比如下使用"find"命令效率高的多。
find /path -type f -exec rm '{}' \;
上面这条命令会对每个文件调用"rm"命令。当然使用新版的"find"也可以得到和"xargs"命令同样的效果:
find /path -type f -exec rm '{}' +
xargs的作用一般等同于大多数中的,但更加灵活易用,并可以正确处理输入中有空格等特殊字符的情况。对于经常产生大量输出的命令如、和来说非常有用。
示例
find . -name "*.foo" | xargs grep bar
该命令大体等价于
grep bar `find . -name "*.foo"`
4.2 xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。
使用示例
(1)find . -perm -7 -print0 | xargs -0 chmod o-w
在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限
(2)find . -type f -print0 | xargs -0 grep "hostname"
用grep命令在所有的普通文件中搜索hostname这个词
(3)find /tmp -name core -type f -print0 | xargs -0 echo "" >/tmp/core.log
在/tmp中查找内存信息转储文件(core dump) ,然后把结果保存到/tmp/core.log 文件中:
4.3 xargs不适合处理带有特殊字符的文本文件及文件名
xargs从标准输入中读取数据,并以空白和换行符分割每个参数(引号中的空白不作为分割符)。然后执行指定的命令(并把分解后的参数附加到命令后面)。如果没有指定具体的命令,默认使用/bin/echo命令。如果没有特别指定,xargs会把`_'当作结束标志。空行在输入时被忽略。
#cat> a <<"EOF"
>it's me!
>over
>EOF
#xargs
xargs: unmatched single quote
因为,Unix文件名允许包含空格和换行符,这样就会在使用xargs时出现问题,在这种情况下最好使用选项'-0',可以阻止这种情况的发生,但使用此选项时要确保此输入流使用null字符作为分隔符。如若与find配合使用,则在find中使用-print0参数。
当文本中出现的特殊字符如单引号',双引号",反斜杆\,下划线_等等字符,当作为参数传给xargs,换行符及其它分隔符很有可能已经被去掉,空行已被忽略,并且也不会简单的理解\和_等字符,从而导致输出的文本与原来的文本不同或直接输出错误信息。
综上所述,在使用xargs是要注意分隔符,并注意测试输出是否与预想相符。这回知道我为什么在上面的find操作时都加了-print0参数了吧,这是防止当文件名包含换行符和空格时不能正常处理。
cut -d: -f1 < /etc/passwd | sort | xargs echo
生成一个系统中所有用户名的压缩列表
4.4 返回值EXIT STATUS
xargs有下列几种返回状态:
0 成功
1-125 不能组装满足指定要求的命令行,一个或多个 Command 参数的调用返回一个非零出口状态,或发生一些其它的错误。
123 if any invocation of the command exited with status 1-125
124 if the command exited with status 255
125 命令被某信号杀死
126 找到命令command但不能执行
127 不能找到命令command
1 其它错误发生
当返回码大于128时,被shell用于表示一个程序由于致命错误( fatal signal)而死亡.
如果不能组装满足指定要求的命令行,则不能调用这个命令,命令的调用被一个信号终止,或一个命令调用以出口状态 255 退出。xargs命令将写一条诊断消息并退出而不处理任何保留的输入。
备注:虽然我是知道了这个东西这么用,但是我还没找到为什么不能用管道直接传给rm参数,而必须通过xargs传给rm呢,今天暂时就这样了,看我什么时候找到这个答案,有哪们前辈,知道答案,也希望能不吝赐教!
参考文献:
1 利用数据库效用给UNIX命名管道
2 UNIX管道和重定向功能在系统备份中的妙用
3 Oracle 管道 解决Exp/Imp大量数据处理问题
4
5 xargs 构造参数列表并运行命令
6 XARGS(1)。
阅读(941) | 评论(0) | 转发(0) |