Linux高级文本处理命令

cut

一、cut命令

  功能:cut命令可以从一个文本文件/文本流中提取文本列

  语法:

  cut -d '分割字符' -f fields  ##用于有特定分割字符

  cut -c 字符区间  ##用于排列整齐的信息

  选项与参数:

  • -d:后面接分隔字符。与 -f 一起使用;
  • -f:依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思
  • -c:以字符(charaters)的单位取出固定字符区间

sed

简介:行编辑器

解决的问题:

  1. 处理文本文件
  2. 分析日志文件
  3. 修改配置文件

sed 的处理流程

  读入一行到模式空间,理解为一个临时缓冲区

  注意:sed 本身就有输出到屏幕这一步

sed的原则

  1. sed 一次只处理一行内容
  2. sed 默认不可以改变文件内容(除非重定向或者用 -i 参数)
  3. 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\nexport PATH=$PATH:$GZW_HOME' profile  ## 里面加了 \n 为换行符
……
#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\n    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\n    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\n    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\)/\1\2/

可能难以理解,我们搞个 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

简介:文本处理工具

解决的问题:

  1. 一堆文本要分析
  2. 一堆数据要处理
  3. 分析服务器日志

同样的,准备一个 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"\t"$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\tUid=%s\n",$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"\tUid="$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\n",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"\t"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"\t"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"\t"$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\tLine\tCol"}{print $1"\t"NR"\t"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 在修改文件上占优势)

 

posted @ 2018-12-07 21:32  小文叔  阅读(810)  评论(0编辑  收藏  举报