跳转至

grep、sed、awk、cut

1 grep

  • 功能:打印匹配行
  • 语法形式:
  • grep [OPTIONS] PATTERN [FILE...]
  • grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
  • 参数选项
  • 基础操作
    • -i:忽略大小写
    • -w:匹配整个单词,如匹配main,main111则不会匹配到
    • -x:匹配整行
    • -m num:最大匹配行数量,比如当一个文件原本有10个匹配行时,设置num=5,则只会打印5条匹配后
    • -A num:同时打印匹配行后num行
    • -B num:同时打印匹配行前num行
    • -v:反向匹配,输出非匹配行内容(正常是打印匹配行,指定了-v则打印非匹配行)
    • -c:统计匹配行数量,与-v一同使用则统计非匹配行数,如grep -cv main test.cc
    • -n:输出匹配行的行号
  • 多文件级操作
    • -l:当查找多个文件时,打印匹配的文件名
    • -L:当查找多个文件时,打印非匹配的文件名
  • 目录级操作
    • -r-R:指定目录搜索而非文件,如grep --include=*.cc --exclude=test1.cc main -r test,在test目录下,包含*.cc文件,排除test1.cc,匹配main
    • --include=GLOB:包含的文件,可以使用模式匹配
    • --exclude=GLOB:排除的文件,可以使用模式匹配
    • --exclude-dir=DIR:排除的子目录,通常在指定目录下有子目录,且不想要匹配时

2 pgrep

  • 功能:基于给定条件来查找正在运行的程序的进程ID。(类似ps和grep的组合体)
  • 语法:pgrep [option] PATTERN
  • -u 用户名:指定所属用户
  • -G 用户组:指定所属组
  • -l:列出进程名
  • -d:指定输出结果分割符,默认一行一个结果
  • 示例
$ ps -ef|grep here4|grep sshd
root     2868240    5518  0 15:01 ?        00:00:00 sshd: here4 [priv]
here4    2868262 2868240  0 15:01 ?        00:00:00 sshd: here4@pts/9
root     3315145    5518  0 17:36 ?        00:00:00 sshd: here4 [priv]
here4    3315159 3315145  0 17:36 ?        00:00:00 sshd: here4@pts/10
here4    3466706 3315177  0 18:25 pts/10   00:00:00 grep --color=auto sshd
$ pgrep -u here4 sshd
2868262
3315159
$ pgrep -l -u here4 sshd
2868262 sshd
3315159 sshd
$ pgrep -l -d ',' -u here4 sshd
2868262 sshd,3315159 sshd

3 awk

  • 官方文档
  • 简单教程
  • 语法形式:管道可以取代files
  • awk [option] script files
  • awk [option] -f scriptfile files
  • 功能:处理文本
  • -F 分隔符:指定分割符(默认每行按空格分割),分隔符可以用单引号包裹,-F与分隔符间可以间隔开,也可以连在一起,如,-F ':'-F:
  • -f scriptfile:指定脚本文件取代script
  • -v 变量名=变量值:赋值一个用户定义变量
  • 示例
# 对test.txt文本每行按空格或TAB分割,打印第1项和第3项的值
awk '{print $1,$3}' test.txt
# 对test.txt文本每行按;分割,打印第1项和第3项的值
awk -F; '{print $1,$3}' test.txt
# -F; 或者-F ';'
awk -F ';' '{print $1,$3}' test.txt
#用awk脚本分析test.txt,test.awk脚本作用与上面中的script一致
awk -f test.awk test.txt
  • 概念
  • 文件的一行称为 awk 的一个记录
  • 使用特定分隔符分开的单词称为字段

3.1 awk 运算符

运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|
&& 逻辑与
~ 和 !~ 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加,减
* / % 乘,除与求余
+ - ! 一元加,减和逻辑非
^ 求幂
++ -- 增加或减少,作为前缀或后缀
$ 字段引用
in 数组成员

3.2 awk内建变量

变量 描述
$n 当前记录的第n个字段,字段间由FS分隔
$0 完整的输入记录
ARGC 命令行参数的数目
ARGIND 命令行中当前文件的位置(从0开始算)
ARGV 包含命令行参数的数组
CONVFMT 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO 最后一个系统错误的描述
FIELDWIDTHS 字段宽度列表(用空格键分隔)
FILENAME 当前文件名
FNR 各文件分别计数的行号
FS 字段分隔符(默认是任何空格)
IGNORECASE 如果为真,则进行忽略大小写的匹配
NF 一条记录的字段的数目
NR 已经读出的记录数,就是行号,从1开始
OFMT 数字的输出格式(默认值是%.6g)
OFS 输出字段分隔符,默认值与输入字段分隔符一致。
ORS 输出记录分隔符(默认值是一个换行符)
RLENGTH 由match函数所匹配的字符串的长度
RS 记录分隔符(默认是一个换行符)
RSTART 由match函数所匹配的字符串的第一个位置
SUBSEP 数组下标分隔符(默认值是/034)

3.3 awk 键值数组

awk支持数组,但key是字符串

3.4 awk 中print和printf的区别

  • print在显示多个结果的时候以逗号分隔,结果将这几部分的内容自动使用分隔符进行分隔,且不需要添加换行符\n
  • printf可以更加灵活的控制某一个字段的输出格式,通过使用诸如%-12s,%3.1f等格式化方法
$ echo -e "hello world bob\ngood bye tim"|awk '{print $1,$3}'
hello bob
good tim
$ echo -e "hello world bob\ngood bye tim"|awk '{printf"%s %s\n",$1,$3}'
hello bob
good tim

3.5 awk脚本语法

注意:当多条语句写在同一行上时,可以用分号来断开语句。 awk脚本分3部分: - BEGIN{ 这里面放的是执行前的语句 } - END{这里面放的是处理完所有的行后要执行的语句 } - {这里面放的是处理每一行时要执行的语句}

3.6 NR的使用

$ cat awk.file 
Tom   19
Jim  20
alice  19
alma  18
$ awk 'NR==1,NR==3{print $0}' awk.file 
Tom   19
Jim  20
alice  19
$ awk 'NR==2{print $0}' awk.file 
Jim  20

3.7 awk if条件语句

注意:if语法与c语言中if完全相同 - 语法:当有多条语句时,可以用花括号包裹

if (condition_1)
    action_1
else if (condition_2)
    action_2
else
    action_3
  • 示例
$ awk 'BEGIN {num = 11; if (num % 2 == 0) printf "%d 是偶数\n", num;else printf "%d 是奇数\n", num}'
10 是偶数

3.8 awk for和while循环

注意:for和while语法与c语言中for和while完全相同 - 语法 - 示例

$ awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'
1
2
3
4
5
$ awk 'BEGIN { i=0;while (++i<5) print i }'
1
2
3
4
$ awk 'BEGIN { i=0;do{print i} while(++i<5)}'
0
1
2
3
4

3.9 awk break和continue

注意:break和continue语法与c语言中break和continue完全相同 - 示例

$ awk 'BEGIN { i=0;do{if(i==3) break;else print i} while(++i<5)}'
0
1
2

4 sed

  • 官方文档
  • 参考文档
  • 功能:流文本处理。sed每次处理一行文本,放入临时缓冲区中,处理完后,输出到标准输出流上(重定向改变输出目标)。
  • 语法:sed [选项]... {脚本(如果没有其他脚本)} [输入文件]
  • 选项参数:
    • -e script:用于串联多个匹配模式,将脚本指令添加到已有指令中
    • -f scriptFile:指定匹配模式的脚本文件
    • -n:不产生命令输出,使用print命令来完成输出,通常与p一起使用
    • -i[suffix]:直接修改文件,-i后面可以带上后缀,表示,修改原文件先备份,备份文件名在原文件名+后缀
    • -r:支持扩展正则表达式
  • 脚本符号
    • s/pattern/replacement/flags:替换字符,flags可选参数
    • g:全局匹配,默认只匹配第一次出现
    • number:匹配第number次匹配的
  • 示例
# 待处理数据可以来自管道,也可以在命令行末尾指定文件路径
# s 用hi取代hello
$ echo "hello world"|sed "s/hello/hi/"
hi world
# 多个指令用;分割
$ echo "hello world"|sed -e "s/hello/hi/;s/world/boy/"
hi boy

4.1 -i修改文本

-i后可以加上备份文件名的后缀,这样会在原文件目录下生成备份文件
  • 示例
$ cat file
hello world!
I'm happy!
$ sed -i.bak "s/hello/hi/" file
$ ls
file  file.bak
$ cat file
hi world!
I'm happy!

4.2 -e添加多个匹配模式

$ sed -e "s/hello/hi/" -e "s/happy/fine/" file
hi world!
I'm fine!

4.3 -f指定脚本文件

# -f指定脚本文件
$ cat sed.script 
s/hello/hi/
s/world/boy/
$ echo "hello world"|sed -f sed.script 
hi boy

4.4 -n与p配合使用打印匹配行

# -n与p配合使用,只打印p指定的内容
$ cat sed.test
hello world
I'm a coder
$ sed -n 's/world/man/p' sed.test
hello man
$ sed  's/world/man/' sed.test
hello man
I'm a coder

4.5 选项统计

4.5.1 命令集

符号 功能
a\ 在当前行下面插入文本。
i\ 前行上面插入文本。
c\ 把选定的行改为新的文本。
d 删除,删除选择的行。
D 删除模板块的第一行。
s 替换指定字符
h 拷贝模板块的内容到内存中的缓冲区。
H 追加模板块的内容到内存中的缓冲区。
g 获得内存缓冲区的内容,并替代当前模板块中的文本。
G 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l 列表不能打印字符的清单。
n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
p 打印模板块的行。
P (大写) 打印模板块的第一行。
q 退出Sed。
b lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file 从file中读行。
t label if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file 写并追加模板块到file末尾
W file 写并追加模板块的第一行到file末尾
! 表示后面的命令对所有没有被选定的行发生作用
= 打印当前行号码。
# 把注释扩展到下一个换行符以前。

4.5.2 替换集

符号 功能
g 表示行内全面替换。(默认每行只匹配第一个)
ng 表示每行只匹配前面n个。(比如2g,每行只匹配前面2个)
i 忽略大小写
p 表示打印行。
w 表示把行写入一个文件。
x 表示互换模板块中的文本和缓冲区中的文本。
y 表示把一个字符翻译为另外的字符(但是不用于正则表达式)
\1 子串匹配标记
& 已匹配字符串标记

4.5.3 匹配模式集

sed 能使用gnu正则表达式,尤其可以配合捕获组可以实现更强大的功能
符号 功能 示例
^ 匹配行开始 /^hello/匹配所有以hello开头的行。
$ 匹配行结束 /world$/匹配所有以worlld结尾的行。
. 匹配一个非换行符的任意字符 /h..ld/匹配h后接2个任意字符,最后是ld的字符串。
* 匹配0个或多个字符 /*world/匹配所有模板是一个或多个空格后紧跟world的行。
[] 匹配一个指定范围内的字符 /[hH]ello/匹配hello或Hello。
[^] 匹配一个不在指定范围内的字符 /[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
\(..\) 匹配子串,保存匹配的字符(需要转义) s/\(love\)able/\1rs/,loveable被替换成lovers。
& 保存搜索字符用来替换其他字符 s/love/I & you/,love这成I love you
\< 匹配单词的开始 /\<love/匹配包含以love开头的单词的行。
> 匹配单词的结束 /love>/匹配包含以love结尾的单词的行。
x{m} 重复字符x,m次 /0{5}/匹配包含5个0的行。
x{m,} 重复字符x,至少m次 /0{5,}/匹配至少有5个0的行。
x{m,n} 重复字符x,至少m次,不多于n次 /0{5,10}/匹配5~10个0的行

4.6 pattern匹配模式规则

  • /pattern/:匹配pattern容行
  • /pattern1/,/pattern2/:匹配pattern1和pattern2行之间内容(包括匹配行)
  • startline,/pattern/:匹配startline行到pattern行之间内容。(如果pattern没有匹配,就会直接匹配到最后一行;如果startline超出了最大行,就匹配失败)
  • /pattern/,endline:匹配pattern行到endline行之间内容。(如果pattern行没有匹配到,匹配就失败;如果endline比pattern匹配所在行小,只会打印pattern匹配的行)
  • linenum:匹配第linenum行
  • startline,endline:匹配startline到endline之间的行
  • startline,+N:匹配startline及其后N行
  • s/pattern/replacement/:替换字符
  • 示例
shw@shu:~$ cat -n /etc/passwd
     1  root:x:0:0:root:/root:/bin/bash
     2  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
     3  bin:x:2:2:bin:/bin:/usr/sbin/nologin
     4  sys:x:3:3:sys:/dev:/usr/sbin/nologin
     5  sync:x:4:65534:sync:/bin:/bin/sync
     6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
     7  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
     8  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
     9  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
    10  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
    11  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
shw@shu:~$ sed -n "6,10p" /etc/passwd
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
shw@shu:~$ sed -n "6p" /etc/passwd
games:x:5:60:games:/usr/games:/usr/sbin/nologin
shw@shu:~$ sed -n "6,+2p" /etc/passwd
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
shw@shu:~$ sed -n "/games/,8p" /etc/passwd
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
shw@shu:~$ sed -n "8,/news/p" /etc/passwd
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
shw@shu:~$ sed -n "/^games/,/news/p" /etc/passwd
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

4.7 查询

4.7.1 p打印匹配行

  • 模式语法:/pattern/p
$ echo "hello world"|sed -n "/^hello/p"
hello world

4.8 修改

4.8.1 s替代匹配项

  • 示例1:替换匹配项
$ echo "hello world"|sed 's/hello/hi/'
hi world
  • 示例2:删除匹配项
# 利用空字符去替换
$ echo "hello world"|sed 's/hello//'
 world

4.9 c改变匹配行

  • 示例
$ echo -e "hello boy\nworld"|sed "/hello/c HELLO BOY"
HELLO BOY
world

4.10 增加

4.10.1 a匹配行后追加行

  • 匹配模式语法:/pattern/a匹配行后追加一行
$ echo hello world"|sed "/^hello/a I am studying sed"
I am studying sed
hello world

4.10.2 i匹配行前追加行

  • 匹配模式语法:/pattern/i匹配行前追加一行
$ echo hello world"|sed "/^hello/i I am studying sed"
I am studying sed
hello world

4.10.3 r将另一个文件内容追加到匹配行后面

  • 匹配模式语法:/pattern/r文件名
$ cat file
hello world
I am studying sed
$ echo "hello world"|sed "/^hello/r file"
hello world
hello world
I am studying sed

4.10.4 w将匹配内容保存到指定文件

  • 匹配模式语法:/pattern/w文件名
$ echo "hello world"|sed "/^hello/w file"
hello world
$ cat file
hello world

4.11 删除

4.11.1 删除匹配行

$ echo -e "hello\nworld"|sed '/he/d'
world

4.11.2 删除指定行

# 删除1-2行
$ echo -e "hello\nworld\nboy"|sed '1,2d'
boy
# 删除第1行
$ echo -e "hello\nworld\nboy"|sed '1d'
world
boy
# 删除第2行
$ echo -e "hello\nworld\nboy"|sed '2d'
hello
boy
# 删除从第一行到最后一行
$ echo -e "hello\nworld\nboy"|sed '1,$d'
# 删除最后一行
$ echo -e "hello\nworld\nboy"|sed '$d'
hello
world

4.11.3 删除空白行

$ echo -e "hello\n\nworld"
hello

world
$ echo -e "hello\n\nworld"|sed '/^$/d'
hello
world

4.12 {}命令组

  • 功能:当命令是另一个匹配模式时,需要使用{}包裹命名
  • 示例:/男/p是另一个匹配模式,需要用{}包裹
$ sed -n '2,4{/男/p}' awk.file 
Jim  20
$ sed -n '2,4/男/p' awk.file 
sed:-e 表达式 #1,字符 4:未知的命令:“/”
$ echo -e "hello world\nboy"|sed -n '1,${/hello/{p;q}}'
hello world

4.13 多行命令

4.13.1 采用多行命令方式

  • 在输入第1条命令后,按回车换行,输入第2条命令,以'结尾输入
$ seq 6|sed '1d
> 3d
> 5d'
2
4
6

4.13.2 使用;单行多条命令

在使用a、c、i (行号插入、改变行、行前插入)时,不能使用此方式,会被解析成单条命令。如下命令`Hello ; 2d`被当成了一条语句
```shell
$ seq 2 | sed '1aHello ; 2d'
1
Hello ; 2d
2
```
$ seq 6 |sed "1d;3s/./333/;5d"
2
333
4
6

4.13.3 使用-e指定多条命令方式

$ seq 6 |sed -e 1d -e 3d -e 5s/./555/
2
4
555
6
  • 作用:针对匹配行再执行sed命令
# 2表示匹配第2行;{s/world/boy/;p}是对第2行的特殊处理,用boy替换匹配的world;p表示打印替换后的内容
$ echo -e "hello\nworld"|sed -n "2{s/world/boy/;p}"
boy

4.14 高阶使用技巧

4.14.1 在匹配行首添加字符

  • 使用&表示匹配的任意内容
$ echo "hello world"|sed "s/hello/#&/"
#hello world

4.14.2 匹配的字符串&

$ echo -e "hello world"|sed 's/hello/[&]/'
[hello] world

4.14.3 匹配子串

子串是\(...\)这里匹配的,由\1,\2等来表示第1额子串,第2个子串

$ echo -e "hello world"|sed 's/\(hello\) \(world\)/\2 \1/'
world hello

4.14.4 使用n每隔多少行跳过

# 1个n表示每隔1行,2个n表示每隔2行,执行后面的指令s/./x/ ,即用x替换任一个匹配的字符
$ seq 6 | sed 'n;n;s/./x/'
1
2
x
4
5
x
$ seq 6 | sed 'n;s/./x/'
1
x
3
x
5
x

5 cut

  • 功能:以行为单位,提取指定数据
  • 语法:cut option file
  • -b [区域规则]:选择指定字节
  • -c [区域规则]:选择指定字符;与-b不同在于,当字符是多字节时,比如汉字,一个汉字就是一个字符,而-b只会以8bit作为计数单位。
  • -d [分割符]:指定分隔符,默认以tab分割
  • -f [区域规则]:与-d结合使用,指定的分割区域
  • 区域规则
    • M:第M个字节、字符、区域,从1开始
    • M,N,...:第M和N个字节、字符、区域(多个用,分割)
    • M-N:第M到N个字节、字符、区域
    • -N行首到第N个字节、字符、区域
    • M-第M个字节、字符、区域到行尾
  • 示例1:-b示例,-c与之想同
# 选择第2个字节
$ echo "hello world"|cut -b 2
e
# 选择从第2字节开始,直到行尾的区域
$ echo "hello world"|cut -b 2-
ello world
# 选择从行首到第2字节的区域
$ echo "hello world"|cut -b -2
he
# 选择从第2字节到第6字节的区域
$ echo "hello world"|cut -b 2-6
ello 
# 选择第2和第3个字节
$ echo "hello world"|cut -b 2,3
el
  • 示例2:-d分隔符
$ echo "hello world boy,girl"|cut -d" " -f 2
world
$ echo "hello world boy,girl"|cut -d" " -f 3
boy,girl
$ echo "hello world boy,girl"|cut -d" " -f 2
world
$ echo "hello world boy,girl"|cut -d"," -f 2
girl
$ echo "hello world boy,girl"|cut -d"," -f 1
hello world boy
$ echo "hello world boy,girl"|cut -d" " -f -2
hello world
$ echo "hello world boy,girl"|cut -d" " -f 2-
world boy,girl
$ echo "hello world boy,girl"|cut -d" " -f 1,3
hello boy,girl