xargs命令使用

前言

在日常的Linux使用中,我们经常需要使用到管道符 “|” 进行命令连接,来处理组合操作,例如:

[root@test ~]# ifconfig | grep -iw inet 
        inet 172.16.220.192  netmask 255.255.255.0  broadcast 172.16.220.255
        inet 127.0.0.1  netmask 255.0.0.0
[root@test ~]# netstat -anlpt | grep -i estab | wc -l
245
[root@test ~]#

管道符的操作是将前一个命令执行后的正确输出作为后一个命令的操作对象执行。

这样的操作可以胜任绝大多数操作环境,但如果是要将前一个命令的正确输出作为后一个命令的参数来执行,有时就显得力不从心了,例如:

[root@test tmp]# touch f1 f2.log
[root@test tmp]# mkdir bd
[root@test tmp]# ls | grep -E .log$ | cp bd/
cp: missing destination file operand after ‘bd/’
Try 'cp --help' for more information.
[root@test tmp]#

本欲将.log结尾的文件拷贝至bd/目录下,但操作却是bd/为拷贝源,而f2.log则为目的,执行失败。可见作为后一个命令的操作对象是放在结尾执行的。

之所说说是操作对象,而不参数,如下操作便可看出来:

[root@test tmp]# ps -ef | awk '/dubbo/ &&!/awk/ {print $2}'                   
3009
[root@test tmp]# ps -ef | awk '/dubbo/ &&!/awk/ {print $2}' | kill -9
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
[root@test tmp]# ps -ef | awk '/dubbo/ &&!/awk/ {print $2}' | jmap
Usage:
    jmap [option] <pid>
        (to connect to running process)
    jmap [option] <executable <core>
        (to connect to a core file)
    jmap [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

where <option> is one of:
    <none>               to print same info as Solaris pmap
    -heap                to print java heap summary
    -histo[:live]        to print histogram of java object heap; if the "live"
                         suboption is specified, only count live objects
    -permstat            to print permanent generation statistics
    -finalizerinfo       to print information on objects awaiting finalization
    -dump:<dump-options> to dump java heap in hprof binary format
                         dump-options:
                           live         dump only live objects; if not specified,
                                        all objects in the heap are dumped.
                           format=b     binary format
                           file=<file>  dump heap to <file>
                         Example: jmap -dump:live,format=b,file=heap.bin <pid>
    -F                   force. Use with -dump:<dump-options> <pid> or -histo
                         to force a heap dump or histogram when <pid> does not
                         respond. The "live" suboption is not supported
                         in this mode.
    -h | -help           to print this help message
    -J<flag>             to pass <flag> directly to the runtime system
[root@test tmp]#

要想让结果作为参数来使用,有多种操作方法,如使用循环:

[root@test tmp]# ps -ef | awk '/dubbo/ &&!/awk/ {print $2}' | while read line ;do jmap $line;done
Attaching to process ID 3009, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.80-b11
0x0000000000400000      7K      /usr/local/jdk1.7.0_80/jre/bin/java
0x00007f5a93797000      66K     /usr/lib64/libbz2.so.1.0.6
0x00007f5a939a7000      153K    /usr/lib64/liblzma.so.5.2.2
0x00007f5a93bcd000      114K    /usr/local/lib/libz.so.1.2.11
0x00007f5a93de8000      97K     /usr/lib64/libelf-0.166.so
0x00007f5a980f1000      19K     /usr/lib64/libattr.so.1.1.0
0x00007f5a982f6000      294K    /usr/lib64/libdw-0.166.so
0x00007f5a9853e000      19K     /usr/lib64/libcap.so.2.22
0x00007f5a98743000      108K    /usr/lib64/libresolv-2.17.so
0x00007f5a9895d000      27K     /usr/lib64/libnss_dns-2.17.so
0x00007f5a9b16f000      86K     /usr/lib64/libgcc_s-4.8.5-20150702.so.1
0x00007f5a9b385000      250K    /usr/local/jdk1.7.0_80/jre/lib/amd64/libsunec.so
0x00007f5a9b6cd000      44K     /usr/local/jdk1.7.0_80/jre/lib/amd64/libmanagement.so
0x00007f5a9b8d5000      113K    /usr/local/jdk1.7.0_80/jre/lib/amd64/libnet.so
0x00007f5a9baec000      89K     /usr/local/jdk1.7.0_80/jre/lib/amd64/libnio.so
0x00007f5aa006c000      64K     /usr/lib64/libnss_myhostname.so.2
0x00007f5aa9bfe000      107K    /usr/local/jdk1.7.0_80/jre/lib/amd64/libzip.so
0x00007f5aa9e16000      60K     /usr/lib64/libnss_files-2.17.so
0x00007f5aaa029000      214K    /usr/local/jdk1.7.0_80/jre/lib/amd64/libjava.so
0x00007f5aaa254000      63K     /usr/local/jdk1.7.0_80/jre/lib/amd64/libverify.so
0x00007f5aaa462000      43K     /usr/lib64/librt-2.17.so
0x00007f5aaa66a000      1115K   /usr/lib64/libm-2.17.so
0x00007f5aaa96c000      14879K  /usr/local/jdk1.7.0_80/jre/lib/amd64/server/libjvm.so
0x00007f5aab7e6000      2068K   /usr/lib64/libc-2.17.so
0x00007f5aabba7000      19K     /usr/lib64/libdl-2.17.so
0x00007f5aabdab000      96K     /usr/local/jdk1.7.0_80/jre/lib/amd64/jli/libjli.so
0x00007f5aabfc0000      140K    /usr/lib64/libpthread-2.17.so
0x00007f5aac1dc000      151K    /usr/lib64/ld-2.17.so
[root@test tmp]#

但这样稍显复杂,所以下面介绍下xargs命令。

xargs

xargs是一条Unix和类Unix操作系统的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。xargs能够处理管道或者stdin并将其转换成特定命令的命令参数。xargs也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。xargs的默认命令是echo,空格是默认定界符。xargs是构建单行命令的重要组件之一。

xargs命令用法:

  • xargs用作替换工具,读取输入数据重新格式化后输出。
    [root@test tmp]# cat testfile 
    a b c d
    e f g h i
    j k l m
    n o p
    q r s
    t u v w
    x y z
    [root@test tmp]# cat testfile | xargs 
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    [root@test tmp]#

    -n选项,指定每行最大参数个数:

    [root@test tmp]# cat testfile | xargs -n 3
    a b c
    d e f
    g h i
    j k l
    m n o
    p q r
    s t u
    v w x
    y z
    [root@test tmp]#

    -d,–delimiter=选项,指定分隔符:

    [root@test tmp]# echo "testZTestZtEstZtesT" | xargs -d Z
    test Test tEst tesT
    
    [root@test tmp]#

    结合-n一起使用:

    [root@test tmp]# echo "testZTestZtEstZtesT" | xargs -d Z -n 2
    test Test
    tEst tesT
    
    [root@test tmp]#
  • 读取stdin,将格式化后的参数传递给下一个命令
    [root@test tmp]# echo "127.0.0.1" | xargs ping -c 1
    PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
    64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
    
    --- 127.0.0.1 ping statistics ---
    1 packets transmitted, 1 received, 0% packet loss, time 0ms
    rtt min/avg/max/mdev = 0.028/0.028/0.028/0.000 ms
    [root@test tmp]#

    默认从stdin中获取的值都是作为参数放在后一个命令的,xargs有选项可以使用替换字符串,在xargs扩展时会被替换掉。
    -I选择,需指定扩展字符串:

    [root@test tmp]# cat testfile | xargs -I {} echo {} -l
    a b c d -l
    e f g h i -l
    j k l m -l
    n o p -l
    q r s -l
    t u v w -l
    x y z -l
    [root@test tmp]# cat testfile | xargs -I [] echo [] -l
    a b c d -l
    e f g h i -l
    j k l m -l
    n o p -l
    q r s -l
    t u v w -l
    x y z -l
    [root@test tmp]#

    -i,–replace选项,同-I{},替换字符串即为{},此选项将会弃用:

    [root@test tmp]# cat testfile | xargs -i echo {} -l
    a b c d -l
    e f g h i -l
    j k l m -l
    n o p -l
    q r s -l
    t u v w -l
    x y z -l
    [root@test tmp]# cat testfile | xargs --replace echo {} -l  
    a b c d -l
    e f g h i -l
    j k l m -l
    n o p -l
    q r s -l
    t u v w -l
    x y z -l
    [root@test tmp]#

    此功能,就可以满足我们一开始的需求:

    [root@test tmp]# tree .
    .
    ├── bd
    ├── f1
    ├── f2.log
    └── testfile
    
    1 directory, 3 files
    [root@test tmp]# ls | grep -E *.log$ | xargs -I{} mv {} bd/
    [root@test tmp]# tree .
    .
    ├── bd
    │   └── f2.log
    ├── f1
    └── testfile
    
    1 directory, 3 files
    [root@test tmp]#
  • xargs结合find使用
    使用rm删除指定文件:

    [root@test tmp]# rm `find /data/ -type f`
    -bash: /usr/bin/rm: Argument list too long
    [root@test tmp]#

    当要删除的文件太多时,就会因为“参数列表过长”错误而无法执行,使用xargs可避免这种问题(所有删除操作都谨慎使用,会无提示直接删除!!!):

    [root@test tmp]# find /data/ -type f -print0 | xargs -0 rm
    [root@test tmp]# mv f1 f1.log
    [root@test tmp]# find ./ -name "*.log" -print0
    ./bd/f2.log./f1.log[root@test tmp]# find ./ -name "*.log" -print0 | xargs -0
    ./bd/f2.log ./f1.log
    [root@test tmp]#

    示例中xargs将find产生的长串文件列表拆散成多个子串,然后对每个子串调用rm。-print0表示输出以null分隔(-print使用换行);-0表示输入以null分隔。这样要比上如下使用find命令效率高的多。

    [root@test tmp]# find /data/ -type f -exec rm -rf {} \;

    上面这条命令会对每个文件调用”rm”命令。当然使用新版的”find”也可以得到和”xargs”命令同样的效果:

    [root@test tmp]# find /data/ -type f -exec rm '{}' +

    查找目录中所有图片并压缩它们:

    [root@test tmp]# find . -type f -name "*.jpg" -print | xargs tar -czvf images.tar.gz

发表评论

error: Content is protected !!