2.5玩转xargs

咱们能够利用管道将一个命令的stdout(标准输出)重定向到另外一个命令的stdin(标准输入)。有些命令只能以命令行参数的形式接受数据,而没法经过stdin接受数据流。这时候就无法使用管道。那么xargs擅长将标准输入数据转换成命令行参数。xargs可以处理stdin并将其转换为特定命令的命令行参数。它也能够将单行或多行文本输入转换成其余格式。html

一、xargs命令应该紧跟在管道操做符以后,以标准输入做为主要的源数据流。如command | xargsshell

二、xargs命令把从stdin接受到 的数据从新格式化,再将其做为参数提供给其余命令。xargs其做用相似于find命令中的exec。安全

a、将多行输入转换成单行输出。只须要将换行符移除,再用“ ”(空格)进行代替,就能够实现多行输入的转换。'\n'被解释成一个换行符,它其实就是多行文本之间的定界符。bash

eg:$cat example.txt工具

1 2 3 4 5 6编码

 7 8 9 10spa

11 12命令行

$ cat example.txt | xargscode

1 2 3 4 5 6 7 8 9 10 11 12htm

b、将单行输入转换成多行输出。

指定每行最大的参数数量n,能够将任何来自stdin的文本划分红多行,每行n个参数。每一个参数都是由“ ”(空格)隔开的字符串。空格是默认的定界符。

eg:$cat example.txt | xargs -n 3

1 2 3

4 5 6

 7 8 9

10 11 12

三、工做原理

a、能够用本身的定界符来分隔参数。用-d选项为输入指定一个定制的定界符。

eg:$echo "splitXsplitXsplitXsplit" | xargs - d X

split split split split

b、结合-n选项,能够将输入划分红多行,而每行包含两个参数:

eg:$echo "splitXsplitXsplitXsplit" | xargs - d X -n 2

split split

split split

四、补充内容

1)、读取stdin,将格式化参数传递给命令

先编写一个小型的定制版echo来更好地理解用xargs提供命令行参数的方法:

#!/bin/bash

#文件名:cecho.sh

echo $* '#'

当参数传递给文件cecho.sh后,它会将这些参数打印出来,并以#字符做为结尾。如

$ ./cecho.sh arg1 arg2

arg1 arg2 #

a、有一个名为args.txt的参数列表文件,以下

$ cat args.txt

arg1

arg2

arg3

能够将这个命令执行屡次,每次使用一个参数:

$ cat args.txt | xargs -n 1 ./cecho.sh

arg1 #

arg2 #

arg3 #

每次执行须要X个参数的命令时,使用:

INPUT | xargs -n X

如:

$ cat args.txt | xargs -n 2 ./cecho.sh

arg1 arg2 #

arg3 #

为了在执行命令时一次性提供全部的参数,可使用:

$cat args.txt | xargs ./ cecho.sh

arg1 arg2 arg3 #

上面例子中,直接为特定的命令(cecho.sh)提供命令行参数。这些参数都源于args.txt文件。但实际上除了以上以外,还须要一些固定不变的命令参数。如

./cecho.sh -p arg1 -1

其中arg1是惟一的可变内容,其他部分都保持不变。咱们能够从文件(args.txt)中读取参数,并按照下面的方式提供给命令:

./cecho.sh -p arg1 -1

./cecho.sh -p arg2 -1

./cecho.sh -p arg3 -1

xargs有一个-I选项,能够提供上面这种形式的命令执行序列。可使用-I指定替换字符串,这个字符串在xarg扩展时会被替换掉。若是将-I与xargs结合使用,对于每个参数,命令都会被执行一次。如

$cat args.txt | xargs -I {} ./cecho.sh -p {} -1

-p arg1 -1 #

-p arg2 -1 #

-p arg3 -1 #

-I {}指定了字符串。对于每个命令参数,字符串{}都会被从stdin读取到的参数替换掉。

注意:使用-I的时候,命令以循环的方式执行。若是有3个参数,那么命令就会连同{}一块儿被执行3次。

2)结合find使用xargs

危险使用:

$find . -type f -name "*.txt" -print | xargs rm -f

这样作很危险,有可能删除没必要要的文件。咱们无法预测分隔find命令输出结果的定界符到底是什么('\n'或者' ').有些文件名中包含空格符,所以xargs极可能会误认为是定界符(hell text.txt会被xargs误解为hell和text.txt)。

只要咱们把find的输出做为xargs的输出做为xargs的输入,就必须将-print0与find结合使用,以字符null(‘\0’)来分隔输出。

用find匹配并列出全部的.txt文件,而后用xargs将这些文件删除:

$find . -type f -name "*.txt" -print0 |xargs -0 rm -f

这样就能够删除全部的.txt文件。xargs -0 将\0做为输入定界符。

3)统计源代码目录中全部c程序文件的行数

统计全部c程序文件的行数(Lines of Code,LOC)。

$find source_code_dir_path -type f -name "*.c" -print0 | xargs -0 wc -1

注意:有关我的源代码更多的统计信息,有个叫作SLOCCount的工具。

d)结合stdin,巧妙运用while语句和子shell

xargs只能以有限的几种方式来提供参数,并且它也不能为多组命令提供参数。要执行包含来自标准输入的多个参数的命令,使用以下:包含while循环的子shell能够用来读取参数,而后经过一种巧妙的方式执行命令:

$cat files.txt | (while read arg; do cat $arg;done)

#等同于cat files.txt | xargs -I {} cat {}

在while循环中,能够将cat $arg替换成任意数量的命令,这样咱们就能够对同一个参数执行多条命令。也能够不借助管道,将输出传递给其余命令。这个技巧可以适用于各类问题场景。子shell操做符内部的多个命令能够做为一个总体来运行。

$cmd0 | (cmd1;cmd2;cmd3) |cmd4

若是cmd1时cd /,那么就会改变子shell工做目录,然而这种改变仅局限于子shell内部。cmd4则彻底不知道工做目录发生了变化。

 转父Shell与子ShellLogin Shell登陆主机后,在执行Bash Script以前,其实咱们已经处于一个BashShell中。这个Shell叫login Shell,是未来咱们执行任何Script的上层环境。又叫父SHell其实每一个账号均可以自定义loginShell。以Linux来讲,账号的login Shell定义在/etc/passwd这个文件中。/etc/passwd的每一行表明一个账号,共有7个字段,之间用:隔开。账号:x:UID 使用者代码:GID 群组代码:用户信息:主目录:login shell路径第二栏x为密码栏,基于系统安全考虑,编码后的密码已经被放入/etc/passwd文件中。login Shell定义在第7个字段,若是这个字段的Shell程序不存在、不合法,或执行失败,则没法登陆主机。父Shell、子Shell当在执行一个Shell Script时,父Shell会根据Script程序的第一行#!以后指定的Shell程序开启一个子Shell环境,而后在子Shell中执行此Shell Script。一旦子Shell中的Script执行完毕,此子Shell随即结束,回到父Shell中,不会影响父Shell本来的环境。子Shell环境拥有与父Shell相同的环境变量、标准输入、输出、错误等。例如:test.sh文件内容#!/bin/bashcd /var/www/html命令行:chmod +x /test.sh命令行:./test.sh执行完脚本后还原到父Shell,而且父Shell并无进入/var/www/html目录。注:这是由于当执行Shell文件时,父Shell会建立子Shell,各自独立。若是须要使用父Shell来执行此脚本,可使用:命令行:. ./test.sh注意.与./之间有一个空格符子Shell继续开启子Shell与父Shell启动子Shell方式同样,继续调用下去,即子Shell开启子Shell。经过$SHLVL变量,能够知道当前所在Shell的层次

相关文章
相关标签/搜索