shell_sed_awk

Sed全名为Stream EDitor,即流式编辑器,行编辑器

sed常用用法

1
2
sed [options] 'script(模式命令)' input_file...
sed [options] -f script_file(sed脚本) input_file...

options

-n 静默模式,不打印模式空间中的内容

-e 执行模式命令,适用于多脚本处理

-i 直接操作原文件

1
2
3
4
5
6
7
sed -n -e '1p' -e '37,40p' /etc/passwd > passwd.txt && cat passwd.txt
# 输出如下
root:x:0:0:root:/root:/bin/bash
rtkit:x:118:126:RealtimeKit,,,:/proc:/bin/false
saned:x:119:127::/var/lib/saned:/bin/false
usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
femn:x:1000:1000:femn,,,:/home/femn:/bin/bash

模式命令 s:替换 p:打印 d:删除 a:增加 g:表示一行上的替换所有的匹配

1
2
3
4
5
6
sed -e '1,37d' /etc/passwd
# 输出如下
saned:x:119:127::/var/lib/saned:/bin/false
usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
femn:x:1000:1000:femn,,,:/home/femn:/bin/bash
mysql:x:121:130:MySQL Server,,,:/nonexistent:/bin/false

a \:在模式匹配到的行后面添加新内容
i 前面

1
2
3
4
5
6
7
8
9
10
sed -e '/root/i \this is head' \
-e '/femn/a \this is tail\n' passwd.txt
# 输出如下
this is head
root:x:0:0:root:/root:/bin/bash
rtkit:x:118:126:RealtimeKit,,,:/proc:/bin/false
saned:x:119:127::/var/lib/saned:/bin/false
usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
femn:x:1000:1000:femn,,,:/home/femn:/bin/bash
this is tail

匹配内容的行’/{content}/‘ 可以使用正则匹配

1
2
3
4
sed -n -e '/\<root\>/s/bin/nologin/p' -e 's/femn/hehe/p' passwd.txt
# 输出如下
root:x:0:0:root:/root:/nologin/bash
hehe:x:1000:1000:femn,,,:/home/femn:/bin/bash

-f 指定文件

1
2
3
4
vim ss
/\<root\>/s/bin/nologin/p
s/femn/hehe/p
sed -n -f ss passwd.txt

sed脚本

1
2
3
4
5
6
vim ss.sh
#!/bin/sed -f
/\<root\>/s/bin/nologin/p
s/femn/hehe/p
chmod a+u ss.sh
./ss.sh passwd.txt

删除注释和空行 显示删除之后的行数

1
2
sed -e '/^#/d' -e '/^$/d' passwd.txt | wc -l
wc -l !$ # 上个文件多少行

个人的一个实用脚本,将中文符号换成英文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
for i in `ls /home/femn/blog/source/_posts/*.md`
do
sed -i -e 's/:/:/g' \
-e 's/;/;/g' \
-e 's/,/,/g' \
-e 's/././g' \
-e 's/(/(/g' \
-e 's/)/)/g' \
-e 's/"/"/g' \
-e 's/"/"/g' \
-e "s/'/'/g" \
-e "s/'/'/g" \
"$i"
done

awk擅于处理列

awk的一些内建变量

FS 输入字段分隔符 默认是空格或Tab

$0 当前记录(这个变量中存放着整个行 的内容)

$1~$n 当前记录的第n个字段,字段间由FS分隔

OFS 输出字段分隔符, 默认也是空格

NR 已经读出的记录数,就是行号

FNR 文件自己的行号

1
2
3
4
5
6
7
8
user_redis=`cat /etc/passwd|grep redis|awk -F : '{print $1}'`
awk 'BEGIN{FS=":"} {print $1,$3,$6}' < passwd.txt
# 如下输出
root 0 /root
rtkit 118 /proc
saned 119 /var/lib/saned
usbmux 120 /var/lib/usbmux
femn 1000 /home/femn

匹配内容

1
2
3
4
5
6
awk -F: '$1=="root" || $1 ~ /femn|mysql/ {print NR, FNR, $1,$3,$6}' OFS="\t" passwd.txt
# 如下输出
1 1 root 0 /root
5 5 femn 1000 /home/femn
# -F: 指定分隔符为':'去分隔文件 默认为空格或Tab
# ~ 表示匹配模式开始./ /中是模式.这就是一个正则表达式的匹配.!~ 表示取反

把指定的列输出到文件

1
2
3
4
5
6
7
8
9
10
11
awk 'NR!=1{if($1 ~ /root|femn/) print > "1.txt"; \
else if($1 ~ /mysql/) print > "2.txt"; \
else print > "3.txt" }' passwd.txt
vim 1.txt
emn:x:1000:1000:femn,,,:/home/femn:/bin/bash
# NR!=1表示不处理表头,所以没有root的那一行
vim 2.txt # 是个空的
vim 3.txt
rtkit:x:118:126:RealtimeKit,,,:/proc:/bin/false
saned:x:119:127::/var/lib/saned:/bin/false
usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false

注意其中的if-else-if语句,可见awk其实是个脚本解释器

统计

1
2
3
4
5
6
7
8
9
10
ll *.txt | awk '{print $5,$9}'
# 输出如下
46 1.txt
0 2.txt
151 3.txt
229 passwd.txt
ll *.txt |awk '{sum+=$5} END {print sum}'
# 输出如下
426

统计每个用户的进程的占了多少内存,sum的RSS那一列

1
ps aux | awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}'

按连接数查看客户端IP

1
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr

awk脚本

1
2
3
4
5
6
7
8
9
awk -F: 'BEGIN {i=1} { if ($7=="/bin/bash") i+=1 } END {print "number "i}' < /etc/passwd
# 输出如下
number 3
vim aa
BEGIN {i=1}
{ if ($7=="/bin/bash") i+=1 }
END {print "number "i}
cat /etc/passwd | awk -F: -f aa

Share Comments