(P1) grep/find/sed/awk tutorial
glob 与正则表达式
glob 与正则表达式都是用来描述通用的字符串模式。然而各种 shell 命令以及编程语言对 glob 与正则表达式的支持各不相同,在写法上也存在较大差异。
glob
具体语法可以参考博客。
Simple Regular Expressions
具体使用方法参考维基百科。总结如下:
., [], [^ ], ^, $, () 均为常见的含义
\n n可以取值为1~9, 例如(ab)c\1表示匹配abcab, 此种用法不被POSIX Extended Regular Expression所接受
a* 表示匹配若干个a
[xyz]* 可以匹配xyx
\1* 例如(a.)c\1*可以匹配abcab, 但不能匹配abcac
\(xx\)* 是非法的写法
POSIX Basic Regular Expression
简称为 BRE,具体使用方法参考维基百科。主要用来向后兼容 Simple RegularExpression
. 用于匹配任意单个字符, 而[a.b]表示a或.或b
[] 特殊情况处理:[]abc], [abc-], [-abc]:匹配]必须放开头, 匹配-必须放开头或结尾
[^] 特殊情况处理:[^]abc], [^-abc], [^abc-]
^ 匹配开头
$ 匹配结尾
*
\{m\}, \{m,\}, \{m,n\}
\(\) 里面被当作是一个单一元素\(ab\)*表示匹配abab
\n 表示匹配第n个括号, 与Simple Regular Expression 兼容, 但不被ERE所使用
许多命令的默认情况下使用 BRE。
POSIX Extended Regular Expression
简称为 ERE,与 BRE 的区别主要在于
{m}, {m,}, {m,n}
() 里面被当作是一个单一元素(ab)*表示匹配abab
\n 非法
Perl Regular Expression
grep
grep 支持的正则表达式语法可参考维基百科,它所支持的正则表达式包含 POSIX Basic Regular Expression。在默认情况(不加例如 -E
等参数时)下,支持如下写法:
*, ., ^, $, [], [^ ], \(\), \n, \{i\}, \{i.j\}. \{i,\}
find
使用 find -regex
时,默认使用 Emacs Regular Expressions,但可以使用 -regextype
来修改这一行为。
find . -type f -name 'a*' # 使用glob
find 命令还可以用来对找到的文件执行命令,例如:
find . -type d -name 'a*' -exec ls {} \;
备注:此处
\;
是必须的,执行逻辑是假定找到的目录名为ab
、ac
,则执行ls ab; ls ac;
也可以使用
+
替换\;
,但此时变为ls ab ac
关于反斜杠为什么是必须的可以参照 stackoverflow。
sed
sed 命令最常见的作用是文本替换,例子如下:
echo -e "abcabc\nabcdef" | sed "s/ab/de/" # 只匹配替换一次
echo -e "abcabc\nabcdef" | sed "s/ab/de/g" # 尽可能多地替换
上述用法的一般形式为:sed "s/pat1/pat2/
,其中 pat1
为将要被替换的字符串,pat2
为替换后的字符串。如果希望 pat1
与 pat2
为正则表达式,则需要使用 -r
选项,例如:
echo -e "hello world\nhello bob" | sed -r "s/hello (.*)/\1/"
sed 命令还有其他的作用
awk
awk 命令的一般形式如下:
awk 'BEGIN {statements_0} pattern {statements_1} END {statements_2}' filename
BEGIN {statements_0}
,pattern
,END {statements_2}
均为可选项,运行原理如下:
- 如果存在
BEGIN {statements_0}
,首先执行statements_0
- 逐行执行:如果该行能与
pattern
匹配,则执行statements_1
的内容 - 如果存在
END {statements_2}
,则执行statements_2
awk 也可接受 stdin 的输入。statements
里可以包含多条命令,不同的命令使用 ;
作为分隔符。
pattern
是一个筛选条件,例如:$1 == 1 && $2 ~ /^ab/
表示满足第一项为1
,第二项满足正则表达式/^ab/
的行,即第二项以ab
为开头。NR < 5
表示第 1 行至第 4 行;NR==2, NR==4
表示第二行至第四行/linux/
表示能匹配正则表达式linux
的行(此例中即为包含linux
字符串的行);!/linux/
表示不能匹配正则表达式linux
的行
statements
例子为print $1
表示打印该行以空格作为分隔符的第一项i++
表示变量i
自加一
- awk 定义了一些内置的特殊变量可以在
statements
使用,例如:NR
表示第几行,NF
表示该行一共有多少项(field),$0
表示整行的文本内容,$1
表示第一项的文本内容,$NF
表示最后一项的文本内容,$(NF-1)
表示倒数第二项的内容。如果需要将分隔符进行修改,可以使用awk -F ,
将分隔符定义为逗号。
例子
awk 可以使用如下方法引入外部变量
var1="a1"; var2="a2"
echo | awk '{print v1 ":" v2}' v1=$var1 v2=$var2
运行结果如下:
a1:a2
echo -e "1,bc\n1,abcd\n2,abc" | awk -F , '$1 == 1 && $2 ~ /^ab/ {print $0}'
运行结果如下:
1,abcd
perl
perl 是一种编程语言,功能强于 sed,引用维基对 sed 的介绍:
sed (“stream editor”) is Unix utility for parsing and transforming text files, with ports available on a variety of operating systems. For many purposes, it has been superseded by perl (or the earlier AWK), but for simple transforms in shell scripts, sed retains some use.