【Shell牛客刷题系列】SHELL15 去掉不需要的单词:总结awk命令中的内置函数

本文深入介绍了awk命令的使用,包括内置变量、函数以及正则表达式的应用。通过实例展示了如何删除含有特定字符的单词,如去除输入中的'B'和'b'。文中还对比了sed和grep命令的用法,帮助读者更好地理解和掌握文本处理工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



该系列是基于牛客Shell题库,针对具体题目进行查漏补缺,学习相应的命令。

刷题链接:牛客题霸-Shell篇

该系列文章都放到专栏下,专栏链接为:《专栏:Linux》。欢迎关注专栏~

本文知识预告:

  • 本文首先总结了awk命令中的各个内置函数的用法;
  • 然后给出了五种题目的解决方法,需要使用到之前学习到的正则表达式。


题目:SHELL15 去掉不需要的单词

写一个bash脚本以实现一个需求,去掉输入中含有B和b的单词。假设输入如下:

big
nowcoder
Betty
basic

你的脚本获取以上输入应当输出:

nowcoder test

说明:你可以不用在意输出的格式,空格和换行都行

相关命令学习

awk:文本和数据进行处理的编程语言

awk命令来自于三位创始人”Alfred Aho,Peter Weinberger, Brian Kernighan “的姓氏缩写,其功能是用于对文本和数据进行处理的编程语言。使用awk命令可以让用户自定义函数或正则表达式对文本内容进行高效管理,与sedgrep并称为Linux系统中的文本三剑客。

语法格式awk 参数 文件

常用参数

参数功能
-F指定输入时用到的字段分隔符
-v自定义变量
-f从脚本中读取awk命令
-mval值设置内在限制

常用的awk内置变量

awk语法由一系列条件和动作组成,在花括号内可以有多个动作,多个动作之间用分号分隔,在多个条件和动作之间可以有若干空格,也可以没有。

变量名称说明
FILENAME当前输入文档的文件名
FNR当前输入文档的当前行号,尤其当多个输入文档时有用
FS设置字段分隔符,默认为空格或制表符
NF当前记录(行)的字段(列)个数
NR输入数据流的当前记录数(行号)
OFS输出字段分隔符,默认为空格
ORS输出记录分隔符,默认为换行符
RS输入记录分隔符,默认为换行符

awk是一种处理文本文件的编程语言,文件的每行数据都被称为记录默认以空格或制表符为分隔符每条记录被分成若干字段(列)awk每次从文件中读取一条记录

例子:

  1. 仅显示指定文件中第1、2列的内容(默认以空格为间隔符):
lucky@DESKTOP-VQ8KID4:~/shell$ awk '{print $1,$2}' nowcoder.txt
#include <iostream>
using namespace
int main()
{
int a
int b
cout <<
return 0;
}
  1. 以冒号为间隔符,仅显示指定文件中第1列的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $1,$2}' /etc/passwd
root x
daemon x
bin x
...
tcpdump x
sshd x
landscape x
pollinate x
lucky x

/etc/passwd文件中的内容由:分隔开。

  1. 以冒号为间隔符,显示系统中所有UID号码大于500的用户信息(第3列):
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '$3>=500' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
  1. 仅显示指定文件中含有指定关键词main的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk '/main/{print}' nowcoder.txt
int main()
  1. 以冒号为间隔符,仅显示指定文件中最后一个字段的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $NF}' /etc/passwd
/bin/bash
/usr/sbin/nologin
/usr/sbin/nologin
...
/usr/sbin/nologin
/bin/false
/bin/bash
  1. 输出行号,NR将所有文件的数据视为一个数据流,而FNR则是将多个文件的数据视为独立的若干个数据流,遇到新文件时行号从1开始重新递增。
lucky@DESKTOP-VQ8KID4:~$ awk '{print NR}' first.txt three.sh
1
2
3
lucky@DESKTOP-VQ8KID4:~$ awk '{print FNR}' first.txt three.sh
1
1
2

grep:强大的文本搜索工具

grep来自于英文词组“global search regular expression and print out the line”的缩写,意思是用于全面搜索的正则表达式,并将结果输出。人们通常会将grep命令与正则表达式搭配使用,参数作为搜索过程中的补充或对输出结果的筛选,命令模式十分灵活。
与之容易混淆的是egrep命令和fgrep命令。如果把grep命令当作是标准搜索命令,那么egrep则是扩展搜索命令,等价于“grep -E”命令,支持扩展的正则表达式。而fgrep则是快速搜索命令,等价于“grep -F”命令,不支持正则表达式,直接按照字符串内容进行匹配。

语法格式: grep [参数] 文件

常用参数:

参数功能
-i忽略大小写
-c只输出匹配行的数量
-l只列出符合匹配的文件名,不列出具体的匹配行
-n列出所有的匹配行,显示行号
-h查询多文件时不显示文件名
-s不显示不存在、没有匹配文本的错误信息
-v显示不包含匹配文本的所有行
-w匹配整词
-x匹配整行
-r递归搜索
-q禁止输出任何结果,已退出状态表示搜索是否成功
-b打印匹配行距文件头部的偏移量,以字节为单位
-o-b结合使用,打印匹配的词据文件头部的偏移量,以字节为单位
-F匹配固定字符串的内容
-E支持扩展的正则表达式
  1. 搜索某个文件中,包含某个关键词的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
  1. 搜索某个文件中,以某个关键词开头的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
  1. 搜索多个文件中,包含某个关键词的内容:
root@DESKTOP-VQ8KID4:~# grep lucky /etc/passwd /etc/shadow
/etc/passwd:lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
/etc/shadow:lucky:$6$SBxuPYFLSnBcfbHN$OkFFnnJCpf2P4OLOnnaWXMq.xbmgL3H5aRy4nkEkk/.8VHABaKDS6MdYm3UR3TpHZplAl5HVyffI8nbLlAAoh1:19256:0:99999:7:::
  1. 搜索多个文件中,包含某个关键词的内容,不显示文件名称:
root@DESKTOP-VQ8KID4:~# grep -h lucky /etc/passwd /etc/shadow
lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
lucky:$6$SBxuPYFLSnBcfbHN$OkFFnnJCpf2P4OLOnnaWXMq.xbmgL3H5aRy4nkEkk/.8VHABaKDS6MdYm3UR3TpHZplAl5HVyffI8nbLlAAoh1:19256:0:99999:7:::
  1. 输出在某个文件中,包含某个关键词行的数量:
root@DESKTOP-VQ8KID4:~# grep -c root /etc/passwd /etc/shadow
/etc/passwd:1
/etc/shadow:1
  1. 搜索某个文件中,包含某个关键词位置的行号及内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -n int nowcoder.txt
3:int main()
5:    int a = 10;
6:    int b = 100;
  1. 搜索某个文件中,不包含某个关键词的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -v int nowcoder.txt
#include <iostream>
using namespace std;
{
    cout << "a + b:" << a + b << endl;
    return 0;
}
  1. 搜索当前工作目录中,包含某个关键词内容的文件,未找到则提示:
root@DESKTOP-VQ8KID4:/# grep -l root *
grep: bin: Is a directory
grep: boot: Is a directory
grep: dev: Is a directory
grep: etc: Is a directory
grep: home: Is a directory
init
grep: lib: Is a directory
grep: lib32: Is a directory
...
grep: tmp: Is a directory
grep: usr: Is a directory
grep: var: Is a directory
  1. 搜索当前工作目录中,包含某个关键词内容的文件,未找到不提示:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -sl main *
nowcoder.txt
  1. 递归搜索,不仅搜索指定目录,还搜索其内子目录内是否有关键词文件:
root@DESKTOP-VQ8KID4:/# grep -srl root /etc
/etc/services
/etc/ltrace.conf
/etc/systemd/logind.conf
/etc/crontab
/etc/newt/palette.ubuntu
/etc/xattr.conf
/etc/apparmor.d/tunables/home
...
  1. 搜索某个文件中,精准匹配到某个关键词的内容(搜索词应与整行内容完全一样才会显示,有别于一般搜索):
lucky@DESKTOP-VQ8KID4:~/shell$ grep -x "return 0;" nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ grep -x "    return 0;" nowcoder.txt
    return 0;
  1. 判断某个文件中,是否包含某个关键词,通过返回状态值输出结果(0为包含,1为不包含),方便在Shell脚本中判断和调用:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -q return nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ echo $?  # 包含
0

lucky@DESKTOP-VQ8KID4:~/shell$ grep -q returns nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ echo $?  # 不包含
1
  1. 搜索某个文件中,空行的数量:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -c ^$ nowcoder.txt
0

awk命令中的内置函数

字符串函数

  1. subgsub函数:sub函数在记录中查找能够匹配正则表达式的最长且最靠左的字串,然后用替换子串替换找到的子串。默认是整个记录,可指定目标字符串。
sub(regualr expression,substitution string);
sub(regualr expression,substitution string,target string);

例子:

lucky@DESKTOP-VQ8KID4:~$ awk '{sub(/now/,"nowcoder"); print}' nowcoder.txt
big
nowcodercoder
Betty
basic
nowcoder

gsub类似于sub的用法,但是sub只对目标串中出现的第一个匹配进行替换。gsub则对字符串中的正则表达式进行全局替换,即替换出现在目标串的每一次匹配成功的子串。

lucky@DESKTOP-VQ8KID4:~$ awk '{gsub(/now/,"nowcoder"); print}' nowcoder.txt
big
nowcodercoder
Betty
basic
nowcoder
  1. index函数:index函数返回子串在字符串中的第一次出现的位置。下标从1开始算起。语法格式为:
index(string, substring)

例子:

lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{print index("hellow", "lo")}'
4
  1. length函数:这个函数很常用,返回字符串的字符个数,支持中文字符。语法格式为:
length(string)

例子:

lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{print length("helloworld")}'
10
  1. substr函数:该函数返回从字符串指定位置开始的一个子串(从1开始算起)。如果指定了子串的长度,则返回字符串相应的部分。如果指定长度超出极限,则返回实际内容。语法格式为:
sbustr(string, starting position, length for substring);

例子:

lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{print substr("Santa Claus",7,6)}'
Claus
  1. match函数:该函数用于返回正则表达式在字符串中出现的位置,如果没有出现,则返回0。其内置变量RSTART保存开始位置,RLEGNTH保存匹配到的长度。语法格式:
match(string,regular expression)

例子:

awk 'BEGIN{start=match("good morning everyone",/n... e/); print start,RSTART,RLENGH}'
  1. split函数:该函数使用有用户自定义的分割符来分割一个字符串,保存到一个数组中。如果没有提供分割符,则使用FS作为分割符。语法格式为:
split(string, array, fieldseparator);
split(string, array);

例子:

lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{split("2013/06/16",date,"/"); print date[2],date[3]}'
06 16
  1. printf函数:同C语言的printf用法。

常用算术函数

  1. int(x)x的整数部分,直接去掉小数部分,不四舍五入。
  2. cos(x)x的余弦值,x是弧度
  3. sin(x)x的正弦值,x是弧度
  4. exp(x)xe的指数函数
  5. log(x)x的自然对数,底数为e
  6. sqrt(x)x的平方根
  7. rand( ):返回一个0到1之间的随机数
  8. srand(x):设定rand的种子,常与rand()一起使用,以产生不同的随机数。例子:
lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{srand(); print rand()}'
0.136167
lucky@DESKTOP-VQ8KID4:~$ awk 'BEGIN{srand(); print rand()}'
0.548888

用户自定与函数

脚本中凡是可以出现模式操作规则的位置都可以放置用户自定义函数。

function function_name(parameter1,parameter2....){
	statements
	return expression
}

注意事项:

  1. 变量的传递是传值调用,而且变量只在该函数中局部有效。数组则是地址引用。
  2. 函数中出现的任何变量,如果不是作为参数列表传进来的,都是全局变量。
  3. 调用函数时1如果没有指定某个形参的值,则设定为空。

题目解决方案

方法一:sed命令

sed '/[Bb]/d' nowcoder.txt

或者

sed '/B\|b/d' nowcoder.txt

方法二:grep命令

grep -v [Bb] nowcoder.txt

方法三:awk正则

awk '!/[Bb]/{print $0}' nowcoder.txt

方法四:awk命令配合match函数

awk '!match($0, /[Bb]/){print $0}' nowcoder.txt

方法五:循环

while read line; do
	if [[ $line =~ [bB] ]]; then
		continue
	else
		echo $line
	fi
done < nowcoder.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗的西瓜瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值