目录
1、通配符与正则表达式
2、grep命令
3、使用sed进行文本替换
4、使用awk进行高级文本处理
1、通配符与正则表达式
名称 | 描述 |
---|---|
通配符 | shell在path name expansion(路径名扩展)时使用,一般使用于文件名匹配,常用于find,ls,cp,mv等命令 |
正则表达式 | 正则表达式用于匹配文本,在文本内容的文本过滤工具里,大都用到正则表达式,如vi,grep,awk,sed等 |
两者的差异: 通配符和正则表达式点像,但是不要混淆。通配符可以理解为只有*,?,[],{}四种符号,正则表达式要复杂的多。*在通配符和正则表达式中有不同的含义,作为通配符表示任意长度的字符,用在正则表达式中表示任意长度的前面字符,不能单独使用。
//匹配邮件的正则表达式
[a-z0-9_]+@[a-z0-9]+\.[a-z]+
//匹配所有的单词
( ?[a-zA-Z]+ ?)
//匹配IP地址
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
2、grep命令
用于文件中的文本搜索
//搜索包含特定模式的文本行
grep pattern filename 或者 grep "pattern" filename
//从stdin中读取数据
echo -e "this is a word\n next line" | grep word
//单个命令对多个文件进行搜索
grep "match_text" file1 file2 file3 ……
//grep命令匹配的文本默认会红色高亮显示,即使没有显示使用--color=auto;
//egrep命令匹配的文本不会高亮显示,需要显示使用--color=auto参数才能高亮显示
grep word filename --color=auto
参数 | 描述 |
---|---|
-E | 正则表达式匹配 |
-o | 只输出文件中匹配到的文本内容 |
-v | 打印除包含match_pattern的之外的所有行 |
-c | 统计文件或者文本中包含匹配字符串的行数 |
-n | 打印出包含匹配字符串的行号 |
-l | 搜索多个文件匹配文本位于哪个文件 |
-i | 忽略样式中的大小写 |
-f | 把需要匹配的内容写在一个文件中用-f参数去匹配这个文件中的内容 |
--inclue/exclude | 在grep搜索中指定或排除文件 |
-q | grep的静默输出。有的时候我们不需要搜索出匹配的文本,我们只需要知道文本在文件中是否匹配,可以使用该参数,然后判断命令是否执行成功,如果文本匹配命令的执行返回值为0执行成功,如果返回为非0则表示不匹配。 |
-A/B/C | 打印出匹配文本之前或之后的行 |
//正则表达式匹配
grep -E "[a-z]+" filename
或者
egrep "[a-z]+" filename
//只输出文件中匹配到的文本内容,结果为line.
echo "this is a line." | grep -o "[a-z]+\."
//统计文件中匹配项的数量
echo -e "1 2 3 4\nhello\n 5 6" | egrep -o "[0-9]" | wc -l
//打印除包含match_pattern的之外的所有行
grep -v match_pattern filename
//统计文件或者文本中包含匹配字符串的行数
grep -c text filename
//打印出包含匹配字符串的行号
grep linux -n example1.txt example2.txt
或者
cat example.txt | grep linux -n
//搜索多个文件匹配文本位于哪个文件,
//-l返回匹配的文件列表,-L返回不匹配的文件列表
grep -l linux example1.txt example2.txt
//忽略样式中的大小写
echo hello world | grep -i "HELLO"
//当前目录递归查找"test_function()"所在的文件的行
grep "test_function()" . -R -n
//用grep匹配多个样式
grep -e "pattern1" -e "pattern"
echo this is a line of text | grep -e "this" -e "line" -o
//把需要匹配的内容写在一个文件中用-f参数去匹配这个文件中的内容
grep -f pattern_filesource_filename
//当前目录中递归搜索所有的.c和.cpp文件
grep "main()" . -r --inclue \*.{c,cpp}
//在搜索中排除所有的README文件
//如果需要排除目录可以使用--exclude-dir选项
//如果需要从文件中读取所需的文件列表,使用--exclude-from FILE
grep "main()" . -r --exclude "README"
//grep的静默输出
grep -q "\$match_text" \$filename
if [ $? -eq 0 ] ; then
echo "The text exists in the file"
else
echo "The does not exist in the file"
fi
seq 10 | grep 5 -A 3 //-A选项,打印出匹配文本之后的3行
seq 10 | grep 5 -B 3 //-B选项,打印出匹配文本之前的3行
seq 10 | grep 5 -C 3 //-C选项,打印出匹配文件前后的3行
使用0值字节作为后缀的grep和xargs
xargs用于将文件名作为命令行参数传递给命令,文件名的分隔符最好是采用0值字节作为分隔符,如果采用空格作为分隔符,如果文件名中包含空格,文件名会被当做两个参数来处理
//为了指明文件名以0值字节作为终止符,需要在xargs中使用-0
grep "test" file* -lZ | xargs -0 rm
3、使用sed进行文本替换
常用于文本替换
sed 's/pattern/replace_string/' file
或者
cat file | sed 's/pattern/replace_string/' //只会替换第一个匹配的文本
cat file | sed 's/pattern/replace_string/g' //会替换匹配的所有文本
cat file | sed 's/pattern/replace_string/Ng' //从第n处开始替换
分隔符可以用:或者|,可以使用双引号,在双引号中可以使用变量
sed 's|原字符|替换至的字符|' filename
sed 's:原字符:替换至的字符:' filename
参数 | 描述 |
---|---|
-i | 默认情况下sed只会打印替换后的文本,不会更改源文件,如果需要更改源文件需要使用-i参数 |
sed -i "" 's/原字符/替换至的字符/' filename //更改会作用于原文件
sed -i命令在mac上使用后面需要跟一个字符串,用来做备份文件,备份文件的名称为原来的名字加上这个字符串的名字;如果这个字符串为空(“”),那就不备份该文件,但是这个空字符不能省略。
高级用法
//移除空白行
sed '/^$/d' file
//直接在文件中进行替换
sed -i "" 's/pattern/replace_string/g' filename
//已匹配字符串标记&。在sed中,我们可以用&标记匹配样式的字符串,
//这样就能够在替换字符串时使用匹配的内容。
echo this is an example | sed 's/\w\+/[&]/g'
输出的结果:this is an example 不是预期的[this] [is] [an] [example]尴尬,不知道是什么原因
//子串匹配标记(\1)。&代表匹配给定样式的字符串。
//但我们也可以匹配给定样式的其中一部分。
//\(pattern\)用于匹配子串,\1代表匹配的一个子串,\2代表匹配的第二个子串
echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
输出的结果:this is 7 in a number
echo seven EIGHT | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
输出的结果:seven EIGHT 不是预期的EIGHT seven 尴尬,不知道是什么原因
//组合多个表达式
sed 'expression' | sed 'expression'
sed 'expression; expression'
sed -e 'expression' -e 'expression'
echo abc | sed 's/a/A/' | sed 's/c/C/' //结果AbC
echo abc | sed 's/a/A/; s/c/C/' //结果AbC
echo abc | sed -e 's/a/A/' -e 's/c/C/' //结果AbC
//引用,sed表达式通常用单引号来引用,当需要在表达式中使用变量的时候可以采用双引号
text=hello
echo hello world | sed "s/$text/HELLO/" //输出结果HELLO world
4、使用awk进行高级文本处理
可以用单引号包含也可以用双引号包含,三个语句块都是可选的
awk语句的执行过程:
首先,执行BEGIN{commands}语句块中的语句;变量初始化、打印输出表格的表头等语句通常都可以写入BEGIN语句块中
接着,从文件或stdin中读取一行,然后执行pattern{commands}。重复这个过程,直到文件全部被读取完毕 ;相当于循环体,每次从文件中读取一行都会执行这部分的命令;若不提供该语句块,则默认执行{print},即打印所读取的每一行。关于print,需要记住两件重要的事情:当print的参数以逗号分隔的时候,参数打印时则以空格作为定界符。在awk的print语句中,双引号是被当做拼接操作符使用的。
最后,当读至输入流末尾时,执行END{commands}语句块;像打印所有行的分析结果这类汇总信息,都是在END语句块中实现的常见任务。
awk 'BEGIN{ print "start" } pattern { commands } END{ print "end" }' file
特殊变量
变量名称 | 含义 |
---|---|
NR | 表示记录数量,在执行过程中对应与当前行号 |
NF | 表示字段数量,在执行过程中对应于当前行的字段数 |
$0 | 这个变量包含执行过程中当前行的文本内容 |
$1 | 这个变量包含第一个字段的文本内容 |
$2 | 这个变量包含第二个字段的文本内容 |
参数 | 描述 |
---|---|
-v | 借助选项-v,我们可以将外部值传递给awk |
getline函数 | awk通常默认读取一个文件的所有行。如果只想读取某一行,可以使用getline函数 |
//借助选项-v,我们可以将外部值传递给awk
eg1:
VAR=10000
echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000
eg2:
var1=luo; var2=hong
echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
luo hong
//使用过滤模式对awk处理的行进行过滤
awk 'NR < 5' //行号小于5的行
awk 'NR==1,NR==5' //行号在1到5之间的行
awk '/linux/' //包含样式linux的行(可以用正则表达式来指定模式)
awk '!/linux/' //不包含模式为linux的行
对目录中的所有文件进行文本替换
//将所有.cpp文件中的Copyright替换成Copyleft
find . -name *.cpp -print0 | xargs -I {} -0 sed -i "" 's/Copyright/Copyleft/g' {}
我们使用find在当前目录下查找所有的.cpp文件,然后使用print0打印出以null字符(\0)作为分隔符的文件列表。(这可以避免文件名中的空格所带来的麻烦。)接着使用通道将列表传递给xargs,后者将对应的文件作为sed的参数,有sed对文件内容进行修改。
补充
1、shell脚本中$#, $0,$1,$2,$?的含义
名称 | 含义 |
---|---|
$# | 脚本的参数个数 |
$0 | 脚本的名称 |
$1 | 脚本的第一个参数 |
$2 | 脚本的第二个参数 |
$? | 上一个执行命令的返回结果(最后运行的命令的结束代码,即返回值) |
练习题
1、统计特定文件中的词频
2、解析文本中的电子邮件地址和URL
3、在文件中移除包含某个单词的句子
网友评论