shell 三剑客(grep,sed,awk)学习
文章目录
- shell 三剑客(grep,sed,awk)学习
- 常用快捷键
- 重定向
- 正则表达式
- grep命令
- 文件正则表达式匹配规则
- sed命令
- 案例
- awk命令
- 内置变量
- awk参数
- 案例
- awk 格式化
- awk模式匹配
- grep练习
- sed练习
- awk练习
在shell中,常用grep,awk,sed进行数据处理
- grep:擅长查找和匹配文本
- awk:擅长编辑和匹配文本内容
- sed:删除格式化文本内容,对文本进行复杂处理
常用快捷键
常用命令
- !! 上一条命令
- !行号 执行history命令
快捷键
- ctrl + a 移动光标到开头。ctrl + e 移动光标到结尾。Alt + 鼠标点击 移动光标到鼠标点击的位置
- ctrl + w 删除光标前的一个单词 ;ctrl + k删除当前光标到行尾的所有内容 ;ctrl + u 删除当前光标到行首所有内容 ;ctrl + y粘贴删除的内容
- clear 清屏。ctrl + k 清屏。ctrl + l 清除一行
重定向
1.输出重定向(>和>>): ifconfig > 1.txt 将输出的内容写到1.txt中. >>是追加写入
2.输入重定向:1.txt > myscript.sh 将文本中的内容当作输入传入脚本中。也就是说脚本需要用户键入信息,就可以将1.txt内容当作用户输入传进去
3.错误重定向(2>): myscript.sh 2> log.txt 将脚本执行的错误写入log.txt中;
myscript.sh &> log.txt 将脚本执行的结果和错误写入log.txt中;
myscript.sh > log.txt 2>&1 将脚本执行的结果写入log.txt中;错误信息也定位到和输出相同的位置
|& 管道服重定向
4.tee将输出同时写入文件中 command | tee 1.txt 2.txt 就是输出的内容可以重定向到多个位置,同时将命令的结果输出到1.txt和2.txt
ls ‘*’ 2>&1 | tee a.txt 输出和错误都重定向到a.txt
直接键盘输入到文本中ctrl + D结束输入
(base) xuguangyu@Mac % tee ~/1.txt > /dev/null
helloworld^D(base) xuguangyu\@Mac ~ % cat ~/1.txt helloworld
5.命令重定向
|可以重定向输入流,将上一条命令的输出流重定向到下一条命令的输入流
正则表达式
基本正则表达式:^$.[]*
扩展正则表达式()[]?+|
grep -E 扩展正则表达式可以分组匹配,匹配多次。
-o 只显示匹配到的内容
()将一个或多个字符捆绑在一起进行处理
\1 第一个匹配的内容
\2 第二个匹配到的内容
grep命令
不区分大小写,且匹配行号。
-i 不区分大小
-n 显示行号
(base) xuguangyu@Mac ~ % grep -i 'root' ~/pwd.txt -n
12\:root:\*:0:0\:System Administrator:/var/root:/bin/sh
13\:daemon:\*:1:1\:System Services\:/var/root:/usr/bin/false
62:\_cvmsroot:\*:212:212\:CVMS Root:/var/empty:/usr/bin/false
文件正则表达式匹配规则
bash中-E (zsh中-e)可以查看文本中的特殊字符,可以看到每一行开头是#,结尾是$
(base) xuguangyu\@Mac ~ % cat -en ~/pwd.txt1 ##\$2 # User Database\$3 # \$4 # Note that this file is consulted directly only when the system is running\$5 # in single-user mode. At other times this information is provided by\$6 # Open Directory.\$
| 或者:或着左边全部,或着右边全部
grep -E "good|dlad" test.txt
匹配到good或者glad
grep -E "g(oo|la)d" test.txt
匹配到good或者glad
sed命令
用来处理文本内容,增加,删除,修改等.;默认是把处理过的和没处理过的一起打印
sed [options] ‘pattern {action}’ file
option:
-n 取消默认输出
-i 直接写入文件.
-e 多次编辑.
-r 支持正则拓展.
pattern可以使用内置命令:
a追加,d删除,i插入,p打印,s/正则/替换/g
案例
1.删除有#的行
sed '/#/d' ~/pwd.txt.
2.打印第2行到第3行
(base) xuguangyu@Mac ~ % sed -n '2,3p' ~/pwd.txt
# User Database
3.从第2行开始往后打印3行
(base) xuguangyu@Mac ~ % sed -n '2,+3p' ~/pwd.txt
\# User Database
\#
\# Note that this file is consulted directly only when the system is running
\# in single-user mode. At other times this information is provided by
4.将第三行开始到结尾的内容全部删除
(base) xuguangyu@Mac ~ % sed '3,$d' ~/pwd.txt
\##
\# User Database
5.替换
-e 执行多次操作,替换两次
sed -e 's/He/I/g' -e 's/abc/123/g' 1.txt
6.添加
a在下一行加,i在上一行加
sed '41a Hello world' 1.txt 在41行后面添加一行Hello world
sed '41i Hello world' 1.txt 在41行前面添加一行Hello world
sed 'a end' 1.txt 在每一行后面加入一行end,不加数字就会对每一行进行处理
7.使用grep和sed案例:取出linux ip地址
方法一
(base) xuguangyu@Mac ~ % ifconfig | grep 'inet ' | sed -e 's/.*inet //g' -e 's/ netmask.*//g'
127.0.0.1
192.168.31.154
方法二
(base) xuguangyu@Mac ~ % ifconfig | sed -n -e '/inet /p' | sed -e 's/.*inet //g' -e 's/ net.*//g'
127.0.0.1
192.168.31.154
方法三
(base) xuguangyu@Mac ~ % ifconfig | sed -ne 's/.*inet //' -e 's/netmask.*//pg'
127.0.0.1
192.168.31.154
-n只显示匹配到的结果 -e多次匹配
如果有多个p,那么多次匹配到的结果都会打印一下,所以只需要打印最后一次匹配的结果即可,s///g替换两次 p打印结果 g全局替换
awk命令
内置变量
默认以空格为分隔符,多个空格也为分隔符
$0 表示一整行
$NF 表示分割后的最后一列
倒数第二列$(NF -1)
NR 表示当前行
FS 分隔符(输入)
OFS 输出分隔符
awk '{print $1}' change.txt 输出第一列
awk '{print $1}' change.txt 输出一整行
加上,输出会多一个空格,自定义输出内容时;必须外层单引号,内层双引号,$1这种不能加引号,否则会识别为文本。
awk参数
一个等于号修改变量,两个等于号关系运算
-F 指定分隔符
-v 定义或着修改内置的变量
-f 从脚本文件中读取awk
案例
1.给每一行添加行号
awk '{print NR,$0}' change.txt
(base) xuguangyu\@Mac \~ % ifconfig | grep 'inet ' | awk '{print NR,\$0}'
1 inet 127.0.0.1 netmask 0xff000000
2 inet 192.168.31.154 netmask 0xffffff00 broadcast 192.168.31.255
2.选择指定行
将第五行到第十行所有内容全部打印
(base) xuguangyu@Mac ~ % cat -n ~/pwd.txt | awk 'NR==5,NR==10{print $0}'5 # in single-user mode. At other times this information is provided by6 # Open Directory.7 #8 # See the opendirectoryd(8) man page for additional information about9 # Open Directory.10 ##
3.awk取出IP地址
默认用空格做分隔,$2代表取第二列的元素
(base) xuguangyu@Mac ~ % ifconfig en0 | awk 'NR==5{print $2}'
192.168.31.154
(base) xuguangyu\@Mac \~ % ifconfig en0
en0: flags=8863 mtu 1500
 options=6460
 ether 6e:4d\:ba:45:5d:44
 inet6 fe80::490\:ffe3\:b738:9dd2%en0 prefixlen 64 secured scopeid 0xb
 inet 192.168.31.154 netmask 0xffffff00 broadcast 192.168.31.255
 nd6 options=201
 media: autoselect
 status: active
(base) xuguangyu\@Mac \~ %
4.以冒号为分隔符得到第一列
awk -F ':' '{print $1}' ~/pwd.txt
NF代表总字端数;$NF代表取最后一个字端的数值
(base) xuguangyu@Mac % awk -F ':' 'NR==20{print $1,$NF}' /pwd.txt
_scsd /usr/bin/false
等价于直接改这个数值
(base) xuguangyu@Mac % awk -v FS=':' 'NR==20{print $1,$NF}' /pwd.txt
_scsd /usr/bin/false
5.修改输出分隔符
OFS修改可以修改输出显示的分隔符
(base) xuguangyu@Mac ~ % awk -F ':' -v OFS='=' 'NR=20{print $1,$NF}' ~/pwd.txt
_scsd===/usr/bin/false
awk 格式化
printf打印:可以格式化打印。默认不打印回车
awk '{printf "第一列:%s\n第二列:%s\n第三列:%s\n",$1,$2,$3}'
一般使用BEGIN打印第一行表头,END打印结尾
awk 'BEGIN{print '在所有动作之前打印'} {print ARGV[0],$0}END{print ‘在所有动作之后’}'
ARGV[0] 代表命令行参数,可以获取命令行参数
awk模式匹配
awk可以匹配到对应行再做处理,具体有三种模式
awk ‘BEGIN{xxxx}模式{xxxx}END{xxx}’
1.空模式 所有行都匹配 awk '{print $0}'所有行都打印出来
2.关系运算符,打印匹配到的行
awk '!/^$/{print $0}'
不打印空行
awk '$5~/^[0-9]{2}$/{print $0}'
匹配正则
awk正则表达式
awk '/^games/{print $0}' pwd.txt
找文件之间的内容
awk '/^operator/,/nologin$/{print $0}'
找到以operator开头到nologin结尾的内容
sort -n排序 uniq去重 wc -l 统计行数
unique -c 统计重复的次数
sort -rn 反转排序结果
head -10 拿到前10行
grep练习
- 找出root相关的行
(base) xuguangyu\@Mac ~ % grep 'root' ~/pwd.txtroot:\*:0:0\:System Administrator:/var/root:/bin/shdaemon:\*:1:1\:System Services\:/var/root:/usr/bin/false\_cvmsroot:\*:212:212\:CVMS Root:/var/empty:/usr/bin/false(base) xuguangyu\@Mac \~ %
2.找出root开头的行
(base) xuguangyu\@Mac ~ % grep '^root' ~/pwd.txtroot:\*:0:0\:System Administrator:/var/root:/bin/sh
3.匹配以root开头的行或着以yu开头的行
(base) xuguangyu\@Mac ~ % grep -E '^(root|yu)' ~/pwd.txtroot:\*:0:0\:System Administrator:/var/root:/bin/sh
注意!!!
要是找root用户和yu用户的行,匹配完整的单词不要root1,yu1,yu2这种.要匹配完整的单词,需要加>
(base) xuguangyu\@Mac ~ % grep -E '^(root|yu)\\>' ~/pwd.txtroot:\*:0:0\:System Administrator:/var/root:/bin/sh
4.过滤bin开头的行,且显示行号
(base) xuguangyu\@Mac ~ % grep -n '^bin' ~/pwd.txt
5.过滤除root开头的行
(base) xuguangyu\@Mac ~ % grep -v '^root' ~/pwd.txt\##\# User Database\#
6.统计yu用户出现的次数
(base) xuguangyu\@Mac ~ % grep '^yu' ~/pwd.txt | wc -l0(base) xuguangyu\@Mac \~ %
使用grep -c
(base) xuguangyu\@Mac ~ % grep -c '^yu' ~/pwd.txt0(base) xuguangyu\@Mac \~
7.匹配yu用户,最多出现2次
(base) xuguangyu@Mac ~ % grep -m 2 '^yu' ~/pwd.txt
8.匹配多个文件,列出存在的信息文件名称
(base) xuguangyu\@Mac ~ % grep "root" ~/pwd.txt \~/pwd2.txt /Users/xuguangyu/pwd.txt\:root:\*:0:0\:System Administrator:/var/root:/bin/sh/Users/xuguangyu/pwd.txt\:daemon:\*:1:1\:System Services\:/var/root:/usr/bin/false/Users/xuguangyu/pwd.txt:\_cvmsroot:\*:212:212\:CVMS Root:/var/empty:/usr/bin/false/Users/xuguangyu/pwd2.txt\:root:\*:0:0\:System Administrator:/var/root:/bin/sh/Users/xuguangyu/pwd2.txt\:daemon:\*:1:1\:System Services\:/var/root:/usr/bin/false/Users/xuguangyu/pwd2.txt:\_cvmsroot:\*:212:212\:CVMS Root:/var/empty:/usr/bin/false(base) xuguangyu\@Mac \~ %
查看哪个文件中包含这条信息
(base) xuguangyu\@Mac ~ % grep -l "root" ~/pwd.txt \~/pwd2.txt/Users/xuguangyu/pwd.txt/Users/xuguangyu/pwd2.txt(base) xuguangyu\@Mac \~ %
9.显示/etc/passwd文件中不以/bin/bash结尾的行
(base) xuguangyu\@Mac \~ % grep -v '/bin/bash\$' /etc/passwd \##\# User Database\# \# Note that this file is consulted directly only when the system is running\# in single-user mode. At other times this information is provided
10.找出/etc/passwd中的两位数或三位数
错误写法
(base) xuguangyu\@Mac \~ % grep -E '\d{2,3}' /etc/passwd\_taskgated:\*:13:13\:Task Gate Daemon:/var/empty:/usr/bin/false\_networkd:\*:24:24\:Network Services\:/var/networkd:/usr/bin/false\_installassistant:\*:25:25\:Install Assistant:/var/empty:/usr/bin/false
正确写法
需要在前后加上<>做闭合排除4位数或更多数字在一起的情况,
(base) xuguangyu\@Mac \~ % grep -E '\<\d{2,3}\>' /etc/passwd\_taskgated:\*:13:13\:Task Gate Daemon:/var/empty:/usr/bin/false\_networkd:\*:24:24\:Network Services\:/var/networkd:/usr/bin/false
11.找出文件中至少一个空白字符开头,后面是非空白字符
(base) xuguangyu\@Mac \~ % grep -E '^\s+\S+' 1.txtI love you 或着(base) xuguangyu\@Mac \~ % grep '^[[:space:]][^[:space:]]' 1.txtI love you
12.找出文件中,所有大小写i开头的行
(base) xuguangyu\@Mac \~ % grep '^[iI]' 1.txt I love you i love you或着-i是忽略大小写 (base) xuguangyu\@Mac \~ % grep -i '^i' 1.txt I love you i love you
13.找出系统上root,yu,nobody用户的信息
(base) xuguangyu\@Mac ~ % grep -E '^(root|yu|nobody)\>' ~/pwd.txtnobody:\*:-2:-2\:Unprivileged User:/var/empty:/usr/bin/falseroot:\*:0:0\:System Administrator:/var/root:/bin/sh14.找出/etc/init.d/functions文件中的所有函数名(base) xuguangyu\@Mac ~ % grep -E '\w+\(\)' ~/functionscheckpid() {\_\_kill\_pids\_term\_kill\_checkpids() {\_\_kill\_pids\_term\_kill() {\_\_pids\_var\_run() {\_\_pids\_pidof() {daemon() {killproc() {pidfileofproc() {pidofproc() {status() {echo\_success() {echo\_failure() {
14.找出/etc/init.d/functions文件中的所有函数名
(base) xuguangyu\@Mac ~ % grep -E '\w+\(\)' ~/functionscheckpid() {\_\_kill\_pids\_term\_kill\_checkpids() {\_\_kill\_pids\_term\_kill() {\_\_pids\_var\_run() {\_\_pids\_pidof() {daemon() {killproc() {pidfileofproc() {pidofproc() {status() {echo\_success() {echo\_failure() {
15.找出用户名和shell相同的用户
base) xuguangyu\@Mac \~ % grep -E '^(\w).*\1$' passwd(base) xuguangyu\@Mac \~ % grep -E '^([^:]+\>).*\1$' passwdsync\:x:5:0\:sync:/sbin:/bin/syncshutdown\:x:6:0\:shutdown:/sbin:/sbin/shutd
sed练习
a.替换⽂件的root为chaoge,只替换⼀次,与替换所有
(base) xuguangyu\@Mac \~ % sed 's/root/chaoge/' pwd2.txt chaoge\:x:0:0\:root:/root:/bin/bashbin\:x:1:1\:bin:/bin:/bin/false(base) xuguangyu\@Mac \~ % sed 's/root/chaoge/g' pwd2.txtchaoge\:x:0:0\:chaoge:/chaoge:/bin/bashbin\:x:1:1\:bin:/bin:/bin/falseba\:x:1002:1002::/home/zhangy:/bin/bash
b.替换⽂件所有的root为chaoge,且仅仅打印替换的结果
(base) xuguangyu\@Mac \~ % sed -n 's/root/chaoge/pg' pwd2.txtchaoge\:x:0:0\:chaoge:/chaoge:/bin/bash
-n和p配合使用
c.替换前10⾏bin开头的⽤户,改为C,且仅仅显示替换的结果
(base) xuguangyu\@Mac \~ % sed -n '1,10s/^bin/C/pg' pwd2.txtC\:x:1:1\:bin:/bin:/bin/false
替换前10⾏b开头的⽤户,改为C,且将m开头的⾏,改为M,且仅仅显
示替换的结果
(base) xuguangyu\@Mac \~ % sed -n -e '1,10s/^b/C/g' -e 's/m/M/pg' pwd2.txtCa\:x:1002:1002::/hoMe/zhangy:/bin/bashdaeMon\:x:2:2\:daeMon:/sbin:/bin/falseMail\:x:8:12\:Mail:/var/spool/Mail:/bin/falseftp\:x:14:11\:ftp\:/hoMe/ftp\:/bin/falsedbus\:x:81:81\:SysteM Message bus\:/:/bin/falsehal\:x:82:82\:HAL daeMon:/:/bin/falseMysql\:x:89:89::/var/lib/Mysql:/bin/falseaaa\:x:1001:1001::/hoMe/aaa:/bin/bashtest\:x:1003:1003::/hoMe/test:/bin/bash(base) xuguangyu\@Mac \~ %
-e多次匹配,每匹配一次就要加一个-e
删除4⾏后⾯所有
(base) xuguangyu\@Mac \~ % sed '4,$d' pwd2.txtroot\:x:0:0\:root:/root:/bin/bashbin\:x:1:1\:bin:/bin:/bin/falseba\:x:1002:1002::/home/zhangy:/bin/bash
删除从root开始,到ftp之间的⾏
(base) xuguangyu\@Mac \~ % sed '/^root/,/^ftp/d' pwd2.txt\&nobody:\$:99:99\:nobody:/:/bin/falsehttp\:x:33:33::/srv/http\:/bin/falsedbus\:x:81:81\:System message bus\:/:/bin/falsehal\:x:82:82\:HAL daemon:/:/bin/falsemysql\:x:89:89::/var/lib/mysql:/bin/falseaaa\:x:1001:1001::/home/aaa:/bin/bashtest\:x:1003:1003::/home/test:/bin/bash(base) xuguangyu\@Mac \~ %
跨行删除
将⽂件中空⽩字符开头的⾏,添加注释符
(base) xuguangyu\@Mac \~ % sed 's/^[[:space:]]/#/g' lovers.txt\#I like my lover.I love my lover.He likes his lovers.\#He loves his lovers.\#she loves her cat
2.删除⽂件的空⽩和注释⾏
(base) xuguangyu\@Mac \~ % sed '/^$/d;/^#/d' lovers.txtI like my lover.I love my lover.
3.给⽂件前三⾏,添加#符号
(base) xuguangyu\@Mac \~ % sed '1,3s/\(^.\)/#\1/g' lovers.txt \# I like my lover.\#I love my lover.\#He likes his lovers.He loves his lovers.\#she loves her cat(base) xuguangyu\@Mac \~ %
注意:()
要使用\(\)
方式
4.sed取出ip地址
(base) xuguangyu\@Mac \~ % ifconfig en0 | sed -n -e 's/^.*inet //g' -e 's/netmask.*$//pg'192.168.31.154 -- mac不备份,替换原文件(base) xuguangyu\@Mac \~ % sed -i '' 's/\(^.\*:.\*\)0x.\*\(".\*\$\\)/\10xabc\2/g' hello.txt
awk练习
1.在当前系统中打印出所有普通⽤户的⽤户和家⽬录(/etc/passwd)
(base) xuguangyu\@Mac \~ % awk -F ':' 'BEGIN{printf "%-10s %-10s\n","用户名","家目录"}$3>1000{printf "%-10s %-10s\n",$1,$(NR-1)}' pwd2.txt用户名 家目录 ba x aaa test (base) xuguangyu\@Mac \~ %
BEGIN打印开头文字
printf 格式化打印
2.给/tmp/chaoge.txt⽂件的前五⾏,添加#号
(base) xuguangyu\@Mac \~ % awk 'NR<=5{print "#",$0}' chaoge.txt\# 爱的魔⼒转圈圈1 爱的魔⼒转圈圈2 爱的魔⼒转圈圈3\# 爱的魔⼒转圈圈4 爱的魔⼒转圈圈5 爱的魔⼒转圈圈6\# 爱的魔⼒转圈圈7 爱的魔⼒转圈圈8 爱的魔⼒转圈圈9\# 爱的魔⼒转圈圈10 爱的魔⼒转圈圈11 爱的魔⼒转圈圈12\# 爱的魔⼒转圈圈13 爱的魔⼒转圈圈14 爱的魔⼒转圈圈15(base) xuguangyu\@Mac \~ %
3.统计⽂本信息
姓名 区号 电话 三个⽉捐款数量
(base) xuguangyu\@Mac \~ % cat info.txt Mike Harrington:\[510] 548-1278:250:100:175Christian Dobbins:\[408] 538-2358:155:90:201Susan Dalsass:\[206] 654-6279:250:60:50Archie McNichol:\[206] 548-1348:250:100:175Jody Savage:\[206] 548-1278:15:188:150Guy Quigley:\[916] 343-6410:250:100:175Dan Savage:\[406] 298-7744:450:300:275Nancy McNeil:\[206] 548-1278:250:80:75John Goldenrod:\[916] 348-4278:250:100:175Chet Main:\[510] 548-5258:50:95:135Tom Savage:\[408] 926-3456:250:168:200Elizabeth Stachelin:\[916] 440-1763:175:75:300(base) xuguangyu\@Mac \~ %
显示所有电话号码
(base) xuguangyu\@Mac \~ % awk -F '[ :]' '!/^$/{print $4}' info.txt548-1278538-2358654-6279548-1348548-1278343-6410298-7744548-1278348-4278548-5258926-3456440-1763(base) xuguangyu\@Mac \~ %
-F
设置切割符号 [: ]
同时设置两个切割符号,空格和:都切
!/^\$/
不匹配空行
显示Tom的电话
(base) xuguangyu@Mac ~ % awk -F '[: ]' '/^Tom/{print $4}' info.txt
926-3456
显示Nancy的姓名、区号、电话
(base) xuguangyu@Mac ~ % awk -F '[: ]' '/^Nancy/{print $2,$3,$4}' info.txt
McNeil [206] 548-1278
显示所有D开头的姓
(base) xuguangyu@Mac % awk -F '[: ]' '$2/^D/{print $2}' info.txt
Dobbins
Dalsass
$2~/^D/代表第二行进行正则匹配
不能用匹配D开头的行
(base) xuguangyu@Mac ~ % awk -F '[: ]' '/^D/{print $2}' info.txt
Savage
显示所有区号是916的⼈名
(base) xuguangyu@Mac ~ % awk -F '[: ]' '$3=="[916]"{print $1}' info.txt
GuyJohnElizabeth(base) xuguangyu\@Mac ~ % awk -F '[: ]' '\$3~/\[916\]/{print $1}' info.txtGuyJohnElizabeth(base) xuguangyu\@Mac \~ %
如果只是字面意思,就需要[916]
变为\[916\]
两种都可以
显示Mike的捐款信息,在每⼀款前加上美元符
(base) xuguangyu@Mac ~ % awk -F '[: ]' '$1=="Mike"{printf "$%s $%s $%s\n",$5,$6,$7}' info.txt
$250 $100 $175
另一种写法
(base) xuguangyu@Mac ~ % awk -F '[: ]' '$1=="Mike"{print "$"$(NF-2)" $"$(NF-1)" $"$NF}' info.txt
$250 $100 $175
显示所有⼈的`姓+逗号+名
(base) xuguangyu@Mac ~ % awk -F '[: ]' -v OFS="," '!/^$/{print $2,$1}' info.txt
Harrington,MikeDobbins,ChristianDalsass,SusanMcNichol,ArchieSavage,JodyQuigley,GuySavage,DanMcNeil,NancyGoldenrod,JohnMain,ChetSavage,TomStachelin,Elizabeth(base) xuguangyu\@Mac \~
OFS可以指定输出分隔符
删除⽂件的空⽩⾏(awk不修改源⽂件),替换后的内容重定向写⼊新⽂
件
(base) xuguangyu@Mac ~ % awk '!/^$/{print $0}' chaoge.txt > chaoge2.txt
(base) xuguangyu\@Mac \~ % cat chaoge2.txt 爱的魔⼒转圈圈1 爱的魔⼒转圈圈2 爱的魔⼒转圈圈3爱的魔⼒转圈圈4 爱的魔⼒转圈圈5 爱的魔⼒转圈圈6爱的魔⼒转圈圈7 爱的魔⼒转圈圈8 爱的魔⼒转圈圈9爱的魔⼒转圈圈10 爱的魔⼒转圈圈11 爱的魔⼒转圈圈12爱的魔⼒转圈圈13 爱的魔⼒转圈圈14 爱的魔⼒转圈圈15爱的魔⼒转圈圈16 爱的魔⼒转圈圈17 爱的魔⼒转圈圈18爱的魔⼒转圈圈19 爱的魔⼒转圈圈20(base) xuguangyu\@Mac \~ %