grep、xargs、sed、awk、xargs

grep

grep 命令很容易学习,它主要有两种使用方式,一种是单独使用,比如搜索某个文件中的内容:

grep 'content' file.txt

或者从标准输入中搜索内容:

echo 'something' | grep 'some'

要想掌握好 grep,重点在于了解它的各种参数。下面是一些常用的参数,如果不记得,后续可以用 man grep 命令来查阅。

grep 在搜索时,默认是大小写敏感的,但如果要搜索 mysql,它可能写做 mysql 也可能写做 MySQL,这就可能存在搜索不到的问题,此时可以用 -i 参数:

echo 'MySQL' | grep -i 'mysql'

如果使用 -n 参数可以打印匹配行的行号,使用 -H 参数可以打印匹配文件的文件名。

默认情况下,如果某个二进制文件中含有搜索的关键词,会显示 Binary file ... matches,使用 -I 选项可以忽略二进制文件,使用 -a选项可以把二进制文件当做文本文件来处理,从而输出匹配的部分。

默认情况下 grep 会展示匹配的那一行,如果想查看上下文,可以使用 -A-B-C 这三个参数:

  1. -A 3:展示匹配行以及后面的 3 行

  2. -B 3:展示匹配行以及前面的 3 行

  3. -C 3:展示匹配行以及前后的 3 行,等价于 -A 3 -B 3

另外一些常用的选项包括 -v,表示只显示那些不匹配的行,-o 表示只显示匹配的部分,-q 表示不输出内容,通常与 if 连用。

xargs

在前面的章节中我们介绍过,可以通过管道将多个命令串联起来,前提是管道后面的命令要支持从标准输入中读取数据,比如前文的 grep 命令。

然而有些命令并不支持从标准输入中读取,比如这样写是无效的:

echo 'file_name' | rm

此时我们可以借助 xargs 命令:

echo "a" | xargs rm

这条命令的原理是,xargs 会把换行符、空格、制表符、EOF等符号做为分隔符,把输入的内容切分为一个数组,并把数组中每一个元素作为参数,放到后面的命令中执行,用伪代码来写就是:

for arg in read_input; do
rm arg
done

很常见的一个坑就是,如果文件名带有空格,比如 hello world 就会被 xargs 截断为两个参数,显然不符合预期。不过一般对内容或者文件进行过滤时,我们都会使用 grepfind,这两个命令都有办法配合 xargs

ls | grep 'a' | tr "\n" "\0" | xargs -0 rm

grep 的话会繁琐一些,需要用 tr 命令把换行符转换成特殊字符 \0,再利用 xargs-0 参数,根据文档所述,这个参数会把分隔符指定为 -0,从而避免了文件名中含有空格的影响。

find 也是类似的原理:

find . -print0 | xargs -0 rm

只不过它自带了 -print0选项,写法更简单。

sed

sed 诞生于 1977 年,已经 41 岁了,这么一位叔叔级别的命令至今还活跃在各种 Shell 脚本中,由此可见它是多么重要。

Mac 自带的时 BSD 版本的 sed,因为功能较弱,我不推荐使用,建议使用 gsed,如无特殊说明,下文的介绍都是针对 gsed的。

brew install coreutils
which gsed
# /usr/local/bin/gsed

sedgrep 的用法类似,都是 sed pattern file 或者 echo 'xx' | sed pattern,也就是说第二个参数可以是文件,也可以从标准输入流中读取。

最标准的用法是进行文本替换(也可以用 tr 命令实现):

echo "a b\nc d"
# a b
# c d
echo "a b\nc d" | gsed 's/a/aa/g'
# aa b
# c d

有时候我们可能不止使用一次 sed,此时可以用 -e 参数把多个命令串联起来:

echo "a b\nc d" | gsed -e 's/a/aa/g' -e 's/b/bb/g'

gsed 中,还可以使用 Shell 里定义的变量:

old=a
new=aa
echo "a b\nc d" | gsed "s/$old/$new/g"

我推荐用 gsed 是因为它有一个 -i 选项,可以对文件进行原地修改:

gsed -i 's/a/aa/g' file

sed 最核心的部分在于这里的 s/a/aa/g,它由若干个斜杠组成(其实也不一定要用斜杠,只要保持一致就行)。这里的 s 表示替换,a 表示待匹配的内容,支持正则,aa 表示替换后的内容,g 表示全部替换,更多的用法有:

  1. 1,3s/a/aa/g:只替换第一到三行中的内容

  2. s/a/aa/1:只替换每行第一个 a

  3. s/a/aa/2g:每行前两个 a 不替换,从第三个开始替换

  4. 2i sss:在第二行前面追加一行,内容为 sss

  5. 1a sss:在第一行后面追加一行,内容为 sss,等价于 2i sss

  6. /a/a sss:遇到有字母 a 的行,就在后面追加一行 sss

  7. 1c sss:把第一行替换为 sss

  8. 2d:删除第二行

这些用法虽然看起来复杂,但是和 vim 一样,每个部分就几种写法,然后自行排列组合即可。

gsed 在默认情况下,会把输入的每一行都输出一遍,它有一个常用的选项是 -n,表示不输出任何一行。通常与 p 命令合用,这个命令可以打印匹配的行,类似于 grep 的效果。

awk

awk 是和 sed 同时代的命令,并称为文本处理两大神器。个人认为 sed 的强大之处在于文本匹配后的处理,而 awk 则更适合文本的结构化处理。

这里以获取 ip 地址的命令来介绍下:

ifconfig | sed -n -e '/127.0.0.1/d' -e '/inet /p' | awk '{print $2}'

这里 awk 的用法其实很简单,就是打印第二列。awk 的核心在于内建的变量:

$0

当前记录(这个变量中存放着整个行的内容)

$1~$n

当前记录的第n个字段,字段间由FS分隔

FS

输入字段分隔符 默认是空格或Tab

NF

当前记录中的字段个数,就是有多少列

NR

已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。

FNR

当前记录数,与NR不同的是,这个值会是各个文件自己的行号

RS

输入的记录分隔符, 默认为换行符

awk 一个很常见的用法是 -f 参数,可以指定输入字段的分隔符:

echo "a;b;c" | awk -F';' '{print $2}'

其实理论上来说,awksed 还要强大,因为它是一个图灵完备的语言,支持 for 循环等等编程思想。建议感兴趣的读者阅读 AWK 简明教程 了解更多 awk 的使用技巧

备注:

1.管道是把一个命令的输出传递给另一个命令作为输入,比如:

command1 | command2
    但是command2仅仅把command1输出的内容作为输入参数。
    find . -name "install.log" -print打印出的是install.log这个字符串,如果仅仅使用管道,那么command2能够使用的仅仅是install.log这个字符串,不能把它当作文件来进行处理。xargs就是为了能够对find搜索到的文件进行操作而编写的,它能把管道传来的字符串当作文件交给其后的命令执行。
举个例子:
(1)$find . -name "install.log" -print | cat
./install.log   #显示从管道传来的内容,仅仅作为字符串来处理
(2)$find . -name "install.log" -print | xargs cat
aaaaaa        #将管道传来的内容作为文件,交给cat执行。也就是说,该命令执行的是如果存在install.log,那么就打印出这个文件的内容。

   通过这个例子,应该很容易理解这样有什么不同了。当你要对匹配文件操作时,使用find and xargs,其实这都是运用了管道。xargs是shell命令的一个,可以把管道输入的内容转化为其参数要操作的文件。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值