cut
一、cut命令
功能:cut命令可以从一个文本文件/文本流中提取文本列
语法:
cut -d '分割字符' -f fields ##用于有特定分割字符
cut -c 字符区间 ##用于排列整齐的信息
选项与参数:
- -d:后面接分隔字符。与 -f 一起使用;
- -f:依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思
- -c:以字符(charaters)的单位取出固定字符区间
sed
简介:行编辑器
解决的问题:
- 处理文本文件
- 分析日志文件
- 修改配置文件
sed 的处理流程
读入一行到模式空间,理解为一个临时缓冲区
注意:sed 本身就有输出到屏幕这一步
sed的原则
- sed 一次只处理一行内容
- sed 默认不可以改变文件内容(除非重定向或者用 -i 参数)
- sed 可以对所有行进行操作,也可以根据正则选定行
sed 的格式
1、命令行格式
sed [options] 'command' file
options: -e,-n,-i(optuions 为可选项)
-e # 执行多次 sed 命令
-n # 忽略默认输出
-i # 修改文件
command:行定位/正则定位+ sed 命令(操作)
2、脚本格式
sed -f scriptfile file
sed 命令
我们复制一个文件,进行操作,内容如下:(nl 就是输出带行号, -b a 就是把空白行也带上行号)
# nl -b a passwd
1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 8 9 halt:x:7:0:halt:/sbin:/sbin/halt 10 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 11 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin 12 operator:x:11:0:operator:/root:/sbin/nologin 13 games:x:12:100:games:/usr/games:/sbin/nologin 14 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin 15 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin 16 nobody:x:99:99:Nobody:/:/sbin/nologin 17 vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin 18 19 20 saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin 21 postfix:x:89:89::/var/spool/postfix:/sbin/nologin 22 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin 23 ntp:x:38:38::/etc/ntp:/sbin/nologin 24 tcpdump:x:72:72::/:/sbin/nologin 25 nscd:x:28:28:NSCD Daemon:/:/sbin/nologin 26 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash 27 apache:x:48:48:Apache:/var/www:/sbin/nologin 28 dockerroot:x:498:497:Docker User:/var/lib/docker:/sbin/nologin
1、p
sed 'p' passwd ## 打印出文件内容,但是每一行打印出了两行
sed -n 'p' passwd ## 忽略默认输出
2、行定位
定位一行
x:行号
sed -n '10p' passwd ## 定位到第 10 行
nl -b a passwd | sed -n '10p' ## 定位到第 10 行
/pattern/:正则
sed -n '/mysql/p' passwd ## 定位到含 mysql 的行
定位几行
x,y:行号
nl -b a passwd | sed -n '10,20p' ## 定位到第 10-20 行
/pattern/,x:正则
sed -n '/nobody/,/sshd/' ## 定位到含有 nobody 的行到含有 sshd 的这一行
x,y!:不选择这一行
nl passwd | sed -n '10!p' ## 不显示第 10 行的内容
nl passwd | sed -n '10,20!p' ## 不显示 10-20 行的内容
间隔几行
first ~ step(first:开始行,step:步进)
nl -b a passwd | sed -n '1~2p' ## 从第一行开始,每两行打印一次
# sed -n '10p' passwd ## 打印第 10 行 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin # sed -n '/nobody/p' passwd ## 打印包含 nobody 的行 nobody:x:99:99:Nobody:/:/sbin/nologin # sed -n '6,10p' passwd ## 打印 6-10 行(包括其中的空白行) sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin # sed -n '/nobody/,/sshd/p' passwd ## 打印 nobody 那一行到 sshd 那一行 nobody:x:99:99:Nobody:/:/sbin/nologin vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin # sed -n '20,/sshd/p' passwd ## 打印从 20 行到 sshd 这一行 saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
# nl -b a passwd | sed -n '1~2p' ## 从第 1 行开始,每 2 行打印一次
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
9 halt:x:7:0:halt:/sbin:/sbin/halt
11 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
13 games:x:12:100:games:/usr/games:/sbin/nologin
15 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
17 vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
19
21 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
23 ntp:x:38:38::/etc/ntp:/sbin/nologin
25 nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
27 apache:x:48:48:Apache:/var/www:/sbin/nologin
3、行处理命令
基本命令
-a(新增行)/i(插入行)
# nl -b a passwd | sed '3aganziwenganziwen' ## 在第 3 行后面新增行,内容为 ganziwenganziwen
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
ganziwenganziwen
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# nl -b a passwd | sed '3iganziwenganziwen' ## 在第 3 行前面插入行,内容为 ganziwenganziwen
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
ganziwenganziwen
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# nl -b a passwd | sed '3,5aganziwenganziwen' ## 在第 3-5 行之间的每一行都新增 ganziwenganziwen
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
ganziwenganziwen
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
ganziwenganziwen
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
ganziwenganziwen
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
# nl -b a passwd | sed '3,5iganziwenganziwen' ## 在第 3-5 行之间的每一行都插入 ganziwenganziwen
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
ganziwenganziwen
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
ganziwenganziwen
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
ganziwenganziwen
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
-c(替换行)
# nl -b a passwd | sed '3c=========' ## 把第 3 行替换成 ======== 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin ========= 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# nl -b a passwd | sed '3,5c=========' ## 把第 3-5 行内所有的内容全部替换成 1 个 ==========
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
=========
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8
9 halt:x:7:0:halt:/sbin:/sbin/halt
-d(删除行)
# nl -b a passwd | sed '3,5d' ## 把 3-5 行全部删除 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
练习1:修改配置文件
在 /etc/profile 中添加环境变量
这里,我只贴出环境变量文件的后几行,以供对比
……
85 #python3.6 86 PATH=$PATH:$HOME/bin:/usr/local/python3/bin 87 export PATH
要解决这个问题有俩难点:1、怎么定位最后一行($ 代表最后一行);2、添加用什么命令
sed 命令如下:
# sed '$a export GZW_HOME=XXX
export PATH=$PATH:$GZW_HOME' profile ## 里面加了
为换行符
……
#python3.6
PATH=$PATH:$HOME/bin:/usr/local/python3/bin
export PATH
export GZW_HOME=XXX
export PATH=$PATH:$GZW_HOME
这么写有个问题,就是假设我们前面要加 4 个空格,而我们是顶格写出来的,怎么办?
解决办法:中间的我们可以加空格,但是第一行加不了空格,需要加一个
# sed '$a export GZW_HOME=XXX export PATH=$PATH:$GZW_HOME' profile ……
#python3.6 PATH=$PATH:$HOME/bin:/usr/local/python3/bin export PATH export GZW_HOME=XXX export PATH=$PATH:$GZW_HOME
注意:这么写只是输出到屏幕的内容修改了,但是我们没有加 options ,所以默认是不会修改到文件内的,那么要直接修改呢?之前我们讲过,要么重定向 ,要么用 -i 参数
# sed -i '$a export GZW_HOME=XXX export PATH=$PATH:$GZW_HOME' profile # cat profile …… #python3.6 PATH=$PATH:$HOME/bin:/usr/local/python3/bin export PATH export GZW_HOME=XXX export PATH=$PATH:$GZW_HOME
而且,重定向有问题,如果我们直接 > 的话,那么会把文件清空了。我们得用 >> 追加写的方式,但是追加写又有个问题,那就是会把显示的全部追加进去,也就是说,配置文件有俩大段一样的,那么怎么弄呢?
出现这个问题的原因就是因为会把默认输出的内容也追加进去我们加个 -n 参数就 ok
# sed -n '$a export GZW_HOME=XXX export PATH=$PATH:$GZW_HOME' profile >> profile
练习2:删除空白行
sed '/^$/d' file ## ^ 代表开头,$ 代表结尾
# sed '/^$/d' passwd
练习3:服务器日志处理——服务器 log 中打印 error 信息
sed -n '/Error/p' file ## 用正则匹配到 Error 信息
# sed -n '/Error/p' catalina.out
替换操作:s
分隔符: /
全局替换: g
例如:
sed 's/nologin/login' passwd ## 将文件内每一行的第一个 nologin 替换成 login
sed 's/:/%/g' passwd ## 将文件内所有的 : 替换成 %
# sed 's/nologin/login/' passwd
……
bin:x:1:1:bin:/bin:/sbin/login
daemon:x:2:2:daemon:/sbin:/sbin/login
adm:x:3:4:adm:/var/adm:/sbin/login
lp:x:4:7:lp:/var/spool/lpd:/sbin/login
……
# sed 's/:/%/' passwd ## 只有第一个 : 换成了 %
root%x:0:0:root:/root:/bin/bash
bin%x:1:1:bin:/bin:/sbin/nologin
# sed 's/:/%/g' passwd ## 加入 g ,则会全部替换
root%x%0%0%root%/root%/bin/bash
bin%x%1%1%bin%/bin%/sbin/nologin
daemon%x%2%2%daemon%/sbin%/sbin/nologin
练习:取出 ifconfig 命令内的 ip 地址
分两步:1、先找到有 ip 的那一行,2、把那一行的除 ip 外的信息换成空字符串
# ifconfig | sed -n '/inet/p' inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0 inet addr:127.0.0.1 Mask:255.0.0.0
# ifconfig | sed -n '/inet .* Bcast/p' ## 正则里面再筛选 .* 代表中间还有内容,后面有 Bcast
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
# ifconfig | sed -n '/inet .* Bcast/p' | sed 's/inet.*r://' ## 这里升级,把 ip 的前半拉替换成空字符(inet开头,r:结尾)
172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
# ifconfig | sed -n '/inet .* Bcast/p' | sed 's/inet.*r://' | sed 's/Bcast.*//' ## 再把 Bcast 后面的全部替换成空字符
172.17.42.1
# ifconfig | sed -n '/inet .* Bcast/p' | sed 's/s+inet.*r://' | sed 's/s+Bcast.*//' ## 上述操作有空白出现,利用 s 代表空白 + 表一个以上符,但是 + 需要转译,所以为 s+
172.17.42.1
sed 高级操作
{} :多个 sed 命令,用 ; 分开(实际操作上,{} 并不是必要的,加了没加还是有点区别)
nl passwd | sed '{10,20;s/false/true/}'
n: 读取下一个输入行(用下一个命令处理)
nl passwd | sed '{n;p}'
nl passwd | sed '{p;n}'
nl passwd | sed '{p;n;n}'
也可以用间隔行进行输出
# sed '{1,3p;s/:/%/}' passwd root:x:0:0:root:/root:/bin/bash root%x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin bin%x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon%x:2:2:daemon:/sbin:/sbin/nologin adm%x:3:4:adm:/var/adm:/sbin/nologin lp%x:4:7:lp:/var/spool/lpd:/sbin/nologin sync%x:5:0:sync:/sbin:/bin/sync shutdown%x:6:0:shutdown:/sbin:/sbin/shutdown …… # sed '{1,3d;s/:/%/}' passwd ## 其实不加 {} 也可以 adm%x:3:4:adm:/var/adm:/sbin/nologin lp%x:4:7:lp:/var/spool/lpd:/sbin/nologin sync%x:5:0:sync:/sbin:/bin/sync shutdown%x:6:0:shutdown:/sbin:/sbin/shutdown halt%x:7:0:halt:/sbin:/sbin/halt ……
# nl -b a passwd | sed -n '{n;p}' ## 第一行被越过了,不打印,所以打印 2,4,6……
2 bin:x:1:1:bin:/bin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
8
10 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
12 operator:x:11:0:operator:/root:/sbin/nologin
14 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
16 nobody:x:99:99:Nobody:/:/sbin/nologin
18
20 saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
22 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
24 tcpdump:x:72:72::/:/sbin/nologin
26 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
28 dockerroot:x:498:497:Docker User:/var/lib/docker:/sbin/nologin
# nl -b a passwd | sed -n '{n;n;p}' ## 第一行以及第二行被跳过,所以打印 3,6,9……,跟 nl -b a passwd | sed -n '{3~3p}' 效果一样
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
9 halt:x:7:0:halt:/sbin:/sbin/halt
12 operator:x:11:0:operator:/root:/sbin/nologin
15 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
18
21 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
24 tcpdump:x:72:72::/:/sbin/nologin
27 apache:x:48:48:Apache:/var/www:/sbin/nologin
&:替换固定的字符串,配合替换操作使用
例如:将 passwd 中用户名后添加空格:
sed 's/[a-z_-]+/& /' passwd
[a-z_-]+代表每行开头的那堆字母,因为不止一个,所以要加 + ,而且要转译;
& 注意,要加的内容在 & 符号后面,我这里是加了一个空格,可能不是特别明显。其实 & 就是匹配我们最前面的正则出来的东西,然后再在后面加空格
# sed 's/[a-z_-]+/& /' passwd root :x:0:0:root:/root:/bin/bash bin :x:1:1:bin:/bin:/sbin/nologin daemon :x:2:2:daemon:/sbin:/sbin/nologin adm :x:3:4:adm:/var/adm:/sbin/nologin lp :x:4:7:lp:/var/spool/lpd:/sbin/nologin sync :x:5:0:sync:/sbin:/bin/sync shutdown :x:6:0:shutdown:/sbin:/sbin/shutdown
将用户名的首字母转换成大写
u l U L
u l:对首字母转大写或小写
U |L:对首一串字符转大写或小写
例如:要求用户名首字母大写
sed 's/[a-z_-]+/u&/' passwd
# sed 's/[a-z_-]+/u&/' passwd Root:x:0:0:root:/root:/bin/bash Bin:x:1:1:bin:/bin:/sbin/nologin Daemon:x:2:2:daemon:/sbin:/sbin/nologin Adm:x:3:4:adm:/var/adm:/sbin/nologin Lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin Sync:x:5:0:sync:/sbin:/bin/sync Shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
练习:将文件夹下的 .txt 文件名转换为大写
ls *.txt | sed 's/^w+/U&/'
# ll total 4512 -rw-r----- 1 root root 4600554 Feb 5 17:00 catalina.out -rw-r--r-- 1 root root 0 Feb 5 21:38 gzw.txt -rw-r--r-- 1 root root 0 Feb 5 21:38 Gzw.txt -rw-r----- 1 root root 5537 Jan 14 17:45 mysqld.log -rw-r--r-- 1 root root 1127 Feb 3 21:29 passwd -rw-r--r-- 1 root root 2067 Feb 4 09:54 profile # ls *.txt | sed 's/^w+/U&/' GZW.txt GZW.txt
# ls | sed 's/.*/U&/' ## 文件名包括格式全部换成大写
CATALINA.OUT
GZW.TXT
GZW.TXT
MYSQLD.LOG
PASSWD
PROFIL
():
( ):替换某种部分字符串 ( 1,2)
s/w1w2w3/w2/
s/w1(w2)(w3)/12/
可能难以理解,我们搞个 txt 看一哈
# cat gzw.txt
w1w2w3
接下来演示一下:
# cat gzw.txt | sed 's/w1(w2)(w3)/1,2/' ## 可以把括号内的理解为把它暂时取出来,用 1 代替,第二个就用 2 代替,中间可以任意家字符,跟替换一样 w2,w3
练习:获取 eth0 的 ip
# ifconfig | sed -n '/inet.*B/p' ## 首先,我们获取到 ip 的这一行 inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
# ifconfig | sed -n '/inet.*B/p' | sed 's/inet.*r:([0-9.]+)+s+B/1/' ## 后面那俩 ip 也跟着出来了
172.17.42.1cast:0.0.0.0 Mask:255.255.0.0
# ifconfig | sed -n '/inet.*B/p' | sed 's/inet.*r:([0-9.]+).+B.*$/1/'
172.17.42.1
练习:获取 passwd 中的用户名 uid ,gid,jid
sed 's/(^[a-z_-]+):x:([0-9]+):([0-9]+):.*$/1,2,3/' passwd
# sed 's/(^[a-z_-]+):x:([0-9]+):([0-9]+):.*$/1,2,3/' passwd root,0,0 bin,1,1 daemon,2,2 adm,3,4 lp,4,7 sync,5,0 shutdown,6,0
r:读取指定文件插入到匹配行
sed '1r 123.txt' abc.txt ## 读文件不会更改文件内容
w:复制匹配行拷贝指定文件里
sed '1w 123.txt' abc.txt ## 写操作会修改目标文件(将 abc.txt 的第一行写入到 123.txt 内,而且是覆盖写)
# cat 123.txt 123 456 789 # cat abc.txt abc def
读:
# sed '1r 123.txt' abc.txt ## 读操作,不改变内容 abc 123 456 789 def # cat 123.txt 123 456 789 # cat abc.txt abc def
写:
# sed '1w 123.txt' abc.txt ## 将 abc.txt 的第一行写入到 123.txt 内 abc def # cat 123.txt abc # cat abc.txt abc def
q:退出 sed 使用 q 可以提前退出 sed
# nl passwd | sed '10q' 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 8 halt:x:7:0:halt:/sbin:/sbin/halt 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin # nl passwd | sed '/nologin/q' 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin
-e:执行多次 sed 命令
# nl -b a passwd | sed -e '10,20d' -e 's/:/%/g' 1 root%x%0%0%root%/root%/bin/bash 2 bin%x%1%1%bin%/bin%/sbin/nologin 3 daemon%x%2%2%daemon%/sbin%/sbin/nologin 4 adm%x%3%4%adm%/var/adm%/sbin/nologin 5 lp%x%4%7%lp%/var/spool/lpd%/sbin/nologin 6 sync%x%5%0%sync%/sbin%/bin/sync 7 shutdown%x%6%0%shutdown%/sbin%/sbin/shutdown 8 9 halt%x%7%0%halt%/sbin%/sbin/halt 21 postfix%x%89%89%%/var/spool/postfix%/sbin/nologin 22 sshd%x%74%74%Privilege-separated SSH%/var/empty/sshd%/sbin/nologin 23 ntp%x%38%38%%/etc/ntp%/sbin/nologin 24 tcpdump%x%72%72%%/%/sbin/nologin 25 nscd%x%28%28%NSCD Daemon%/%/sbin/nologin 26 mysql%x%27%27%MySQL Server%/var/lib/mysql%/bin/bash 27 apache%x%48%48%Apache%/var/www%/sbin/nologin 28 dockerroot%x%498%497%Docker User%/var/lib/docker%/sbin/nologin
小技巧:如果在 sed 命令的正则表达式内,要使用我们的系统变量怎么办呢?两个方式
1.sed命令使用双引号的情况下,使用$var直接引用
$ echo|sed "s/^/$RANDOM.rmvb_/g" 29328.rmvb_
# 上面例子引用了一个环境变量$RANDOM的值
2.sed命令使用单引号的情况下,使用'"$var"'引用,单引号里面加双引号,全为因为形式的引号
类似,我们可以看到
$ echo|sed 's/^/'"$RANDOM"'.rmvb_/g' 31338.rmvb_
面试题:
1、修改某个目录下所有包含 aaa 文件的文件名,将 aaa 改成 AAA,目录结构树如下:
# tree
.
├── aaa.txt
├── aba
│ ├── aaaA.txt
│ ├── aaa.txt
│ ├── Abaaa.txt
│ └── ABA.txt
├── Abaaa.txt
└── BBB
├── aaa.txt
└── ABAB.txt
写法:
# find . -name '*aaa*' -exec rename aaa AAA {} ; # tree . ├── AAA.txt ├── aba │ ├── AAAA.txt │ ├── AAA.txt │ ├── AbAAA.txt │ └── ABA.txt ├── AbAAA.txt └── BBB ├── AAA.txt └── ABAB.txt
1、修改某个目录下所有文件中包含 aaa,将文件内的 aaa 改成 AAA
步骤:首先把把包含 aaa 的这些文件给找出来,其次再把 aaa 改成 AAA
# grep aaa abc.txt ## 这行命令的意思是,在 abc.txt 内找出有 aaa 的行
aaa
aaaBB
# grep aaa -rl . ## 代表递归,在当前目录下找出所有含有 aaa 的文件
./abc.txt
./qwe.txt
./456/lala.txt
# sed 's/aaa/AAA/g' `grep aaa -rl .` ## 这里注意要加全局 g ,不加的话,假设有个 aaaaaa ,那么只会替换前面的 aaa
AAA
AAA
AAABB
aaAa
gzw
a
aa
AAaaA
1234
qwe
a
AAA
AAA
A
s
e
AAAA
aa
A
aaA
AAA
aAaa
AAaaAaAAAA
# sed -i 's/aaa/AAA/g' `grep aaa -rl .` ## 真正要修改要加 -i 参数
awk
简介:文本处理工具
解决的问题:
- 一堆文本要分析
- 一堆数据要处理
- 分析服务器日志
同样的,准备一个 passwd 文件
# nl -b a passwd 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 8 9 halt:x:7:0:halt:/sbin:/sbin/halt 10 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 11 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin 12 operator:x:11:0:operator:/root:/sbin/nologin 13 games:x:12:100:games:/usr/games:/sbin/nologin 14 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin 15 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin 16 nobody:x:99:99:Nobody:/:/sbin/nologin 17 vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin 18 19 20 saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin 21 postfix:x:89:89::/var/spool/postfix:/sbin/nologin 22 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin 23 ntp:x:38:38::/etc/ntp:/sbin/nologin 24 tcpdump:x:72:72::/:/sbin/nologin 25 nscd:x:28:28:NSCD Daemon:/:/sbin/nologin 26 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash 27 apache:x:48:48:Apache:/var/www:/sbin/nologin 28 dockerroot:x:498:497:Docker User:/var/lib/docker:/sbin/nologin
内置参数
$0:表示整个当前行
$1:每行第一个字段
$2:每行第二个字段
$n:每行第 n 个字段
awk 的参数:分隔符
-F separator 设定分隔符(默认为空格)
# awk -F ':' '{print $1}' passwd ## 以 : 为分隔符,打印第一列 root bin daemon adm lp sync shutdown
…
打印多个字段
# awk -F ':' '{print $1,$3}' passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 # awk -F ':' '{print $1" "$3}' passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 # awk -F ':' '{print $1"userid:"$3}' passwd rootuserid:0 binuserid:1 daemonuserid:2 admuserid:3 lpuserid:4 syncuserid:5 shutdownuserid:6 # awk -F ':' '{printf("Username:%s Uid=%s ",$1,$3)}' passwd ## 可以用 printf 函数形式输出 Username:root Uid=0 Username:bin Uid=1 Username:daemon Uid=2 Username:adm Uid=3 Username:lp Uid=4 Username:sync Uid=5 Username:shutdown Uid=6
# awk -F ':' '{print "Username:"$1" Uid="$3}' passwd ## 和上述效果一致
Username:root Uid=0
Username:bin Uid=1
Username:daemon Uid=2
Username:adm Uid=3
Username:lp Uid=4
Username:sync Uid=5
NR:每行的行号
NF:字段数量(相当于列,一行有多少个列)
FILENAME:正在处理的文件名
# awk -F ':' '{print NR,NF,FILENAME}' passwd ## 第一行 7 列,文件名为 passwd 1 7 passwd 2 7 passwd 3 7 passwd 4 7 passwd 5 7 passwd 6 7 passwd
练习:显示 /etc/passwd 每行的行号,每行的列数对应的用户名
# awk -F ':' '{print "行号:" NR,"列数:"NF,"文件名:"$1}' passwd
行号:1 列数:7 文件名:root
行号:2 列数:7 文件名:bin
行号:3 列数:7 文件名:daemon
行号:4 列数:7 文件名:adm
行号:5 列数:7 文件名:lp
行号:6 列数:7 文件名:sync
行号:7 列数:7 文件名:shutdown
# awk -F ':' '{printf("行号:%s列数:%s用户名:%s ",NR,NF,$1)}' passwd
行号:1列数:7用户名:root
行号:2列数:7用户名:bin
行号:3列数:7用户名:daemon
行号:4列数:7用户名:adm
行号:5列数:7用户名:lp
行号:6列数:7用户名:sync
行号:7列数:7用户名:shutdown
练习:显示 /etc/passwd 中用户 ID > 100 的行号以及用户名
# awk -F ':' '{if ($3>100) print $1,$3}' passwd saslauth 499 dockerroot 498
练习:在服务器的 apache 日志中找出 ip: 139.162.88.63 的访问日期
日志的格式如下:
139.162.88.63 - - [06/Feb/2019:17:03:23 +0800] "GET http://clientapi.ipip.net/echo.php?info=1234567890 HTTP/1.1" 404 290 "-" "Go-http-client/1.1" 149.34.44.174 - - [06/Feb/2019:20:27:59 +0800] "GET / HTTP/1.1" 403 4961 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
有两种方式:
# sed -n '/139.162.88.63/p' access_log | awk '{print $1" "substr($4,2)}' ## 利用sed 找出行再处理;substr是截取字符串函数,不用的话,从 1 开始,不用的话,会有 [ 出现 139.162.88.63 13/Jan/2019:17:21:22 139.162.88.63 14/Jan/2019:18:56:59 139.162.88.63 15/Jan/2019:19:43:35 139.162.88.63 17/Jan/2019:19:12:26 139.162.88.63 20/Jan/2019:19:59:47 139.162.88.63 22/Jan/2019:17:16:44 139.162.88.63 24/Jan/2019:21:32:20 139.162.88.63 26/Jan/2019:23:09:01 139.162.88.63 28/Jan/2019:19:02:10 139.162.88.63 29/Jan/2019:17:34:58 139.162.88.63 30/Jan/2019:18:00:42 139.162.88.63 31/Jan/2019:20:00:52 139.162.88.63 01/Feb/2019:20:42:48 139.162.88.63 03/Feb/2019:17:50:28 139.162.88.63 04/Feb/2019:19:48:18 139.162.88.63 05/Feb/2019:21:04:14 139.162.88.63 06/Feb/2019:17:03:23 # awk '/139.162.88.63/{print $1" "substr($4,2)}' access_log ## 直接先用正则匹配出行
139.162.88.63 13/Jan/2019:17:21:22 139.162.88.63 14/Jan/2019:18:56:59 139.162.88.63 15/Jan/2019:19:43:35 139.162.88.63 17/Jan/2019:19:12:26 139.162.88.63 20/Jan/2019:19:59:47 139.162.88.63 22/Jan/2019:17:16:44 139.162.88.63 24/Jan/2019:21:32:20 139.162.88.63 26/Jan/2019:23:09:01 139.162.88.63 28/Jan/2019:19:02:10 139.162.88.63 29/Jan/2019:17:34:58 139.162.88.63 30/Jan/2019:18:00:42 139.162.88.63 31/Jan/2019:20:00:52 139.162.88.63 01/Feb/2019:20:42:48 139.162.88.63 03/Feb/2019:17:50:28 139.162.88.63 04/Feb/2019:19:48:18 139.162.88.63 05/Feb/2019:21:04:14 139.162.88.63 06/Feb/2019:17:03:23
逻辑判断式
~,!~ :匹配正则表达式
==,!=,<,> :判断逻辑表达式
# awk -F ':' '$1~/^m.*/{print $1}' passwd ## 以 m 开头的用户名 mail mysql # awk -F ':' '$1!~/^m.*/{print $1}' passwd ## 不以 m 开头的用户名 root bin daemon adm lp sync shutdown
# awk -F ':' '$3>100{print $1" "$3}' passwd
saslauth 499
dockerroot 498
扩展格式
command 扩展
BEGIN{print "start"}pattern{awk 命令}END{print "END"} ## 最开始先执行 BEGIN 后面的花括弧内容,再执行 awk 内的,最后再执行 END 花括弧内的
练习:制表显示 /etc/passwd 每行的行号,每行的列数,对应的用户名
# awk -F ':' 'BEGIN{print"User Line Col"}{print $1" "NR" "NF}END{"===="FILENAME"===="}' passwd User Line Col root 1 7 bin 2 7 daemon 3 7 adm 4 7 lp 5 7 sync 6 7 ====passwd====
练习:统计当前文件夹下的文件/文件夹占用的大小
# ll total 513984 -rw-r--r-- 1 root root 137514 Jan 14 17:51 1.log -rw-r--r-- 1 root root 177462 Jan 26 15:34 2.log -rw-r--r-- 1 root root 165223 Jan 26 15:46 3.log -rw-r--r-- 1 root root 273507 Jan 26 14:32 5.log -rw------- 1 root root 525542481 Feb 3 16:12 heap.bin drwxr-xr-x 2 root root 4096 Jan 26 16:02 scripts drwxr-xr-x 2 root root 4096 Feb 6 20:41 test # ll | awk 'BEGIN{count==0}{count+=$5}END{print count}' 526304379
# ll | awk 'BEGIN{count==0}{count+=$5}END{print count/1024/1024 "Mb"}'
501.923Mb
练习:统计显示 /etc/passwd 的账户总人数
# awk -F ':' 'BEGIN{count==0}{count++}END{print count}' passwd ## 每行其实就是个用户,但是这样写其实是把空行也计算进去了 28
# awk -F ':' 'BEGIN{count==0}$1!~/^$/{count++}END{print count}' passwd ## 用正则排除空行
25
练习:统计显示 /etc/passwd 中 uid > 100 的用户名
# awk -F ':' 'BEGIN{count==0}$3>100{user[count++]=$1}END{for(i=0;i<count;i++) print i,user[i]}' passwd 0 saslauth 1 dockerroot
练习:统计 access_log 日志中每个 ip 出现的次数
# awk '{arr[$1]++}END{for(key in arr) print key,arr[key]}' access_log 39.104.135.252 1 155.138.161.210 1 64.68.233.90 1 171.117.239.207 1 36.78.107.210 1 177.188.145.39 1 177.84.43.202 1 106.15.176.145 1 103.110.164.134 1 36.67.146.11 1 94.241.165.85 1 37.115.184.19 9 139.224.15.159 1 198.20.87.98 5 103.204.166.138 1 101.132.97.6 1 106.14.168.238 3
…
awk vs sed
awk 和 sed 都可以处理文本
awk 侧重于复杂逻辑处理
sed 侧重于正则处理
awk 和 sed 可以共同使用(统计上,awk 占点优势;sed 在修改文件上占优势)