sed

  1. 命令格式
  • 基本命令
sed [option] '[address[,address]][!]command[arguments]' [file]

command为编辑命令:
d 删除
p 打印 ( option搭配参数 -n 则只输出匹配的行 )
a 追加
i 插入
c 更改

address表示地址范围:
4 第四行
$ 最后一行(需要用单/双引号括起来)

​在address后边的 ! 使sed将相应的命令command作用于所有与该地址不匹配的行。即该地址/范围不执行命令command。​

  • 替换
sed [-in] '[address]s/pattern/replacement/flags' [file]

flags(在有意义的情况下可以组合使用):
n 1~512之间的一个数字,表示对本模式中指定模式第n次出现的情况进行替换
g 对模式空间的所有出现情况进行全局替换。当没有g时只有第一次出现会被替换。
p 打印模式空间的内容
w file 将模式空间的内容写到文件file中
2 一个数字(1, 23,...),表示替换第几个匹配的内容。1为默认值。

replacement中的特殊字符
& 引用用正则表达式匹配的内容
\n 引用第n(1~9的数字)个分组内容(分组内容通过pattern中的“ \( ”和“ \)
  • 删除
sed '[address|pattern]d' [file]
删除address描述范围或者匹配pattern的行

如删除空行
sed -i '/^\s*$/d' file
  • 增删改
sed [address]a\
text

sed [address]i\
text

sed [address]c\
text

这里的\用来转义行尾的回车换行符
  • 列表
显示文件中的不可显字符
sed -n '1,10p' -e 'l' node2.log
head node2.log | sed -e 'l'

在sed中不能使用ASCII值来匹配字符。

  • 命令集
使用的命令
sed -f <cmdsetfile> file

cat cmdsetfile
/UNIX$/{
N
s/\nSystem/Operating &/
P
D
}
命令集的多个命令也可以在命令行中使用;连接使用。
  1. 改变控制流顺序
  • sed的正常控制流
  • sed与awk_sed awk

  • 步骤1到步骤4,周而复始。
  • 处理多行模式空间(N、D、P)

多行模式空间:

sed与awk_分隔符_02

单行模式命令

解释

多行模式命令

解释

d

删除整个模式空间的内容,再读入新行。

D

只删除多行模式空间的第一行,不读入新行。命令集的第一条命令重新作用于模式空间的剩余内容。

n

读入一行并覆盖原有内容。

N

读入新行并添加到模式空间现有内容之后。原有的行和新添加的行之间用换行符(\n)分割。^匹配模式空间中的第一个字符的开始位置,$匹配模式空间中的最后的换行符。

p

在执行完所有命令后模式空间的内容会自动输出。sed -n选项抑制这个默认动作。此外,命令集中的最后一条命令无法执行时也不会默认输出(D命令就能达到这个效果)。此时需要p/P命令帮助输出。这里p命令会输出模式空间中的所有内容。

P

输出多行模式空间中的第一行(Line 1),行结尾是第一个\n。

​注:sed命令的逐行读入过程与上述命令是独立的。即sed的读入一行在命令集读入一行的流程之外。​

  • 采用保持空间来保存模式空间的内容并使它可以用于命令(H、h、G、g、x)

模式空间(Pattern Space)是当前输入行的缓冲区,而保持空间(Hold Space)是另一个文本缓冲区。模式空间和保持空间可以相互复制数据。相关命令如下:

命令

缩写

功能

hold

h

将模式空间的内容复制到保持空间,且覆盖原保持空间的内容。

Hold

H

将模式空间的内容追加到保持空间的尾部。

get

g

将保持空间的内容复制到模式空间,且覆盖原模式空间的内容。

Get

G

将保持空间的内容追加到模式空间的尾部。

Exchange

x

交换保持空间和模式空间的内容。

sed与awk_sed_03


命令(H、h、G、g、x)中的每一个都可以利用一个地址来指定一行或者行范围。

小写字母命令​​改写​​​目的缓冲区的内容,大写字母命令​​追加​​缓冲区的现有内容。

H命令在保持空间的内容之后放置一个换行符,且后边跟随模式空间的内容(即使保持空间是空的,换行符也被追加到保持空间中)。G命令在模式空间的内容之后放置一个换行符,且后面跟随保持空间的内容。

例子

grep "^\.XX" $* | sort -u |
#或者使用;来分割sed命令
sed '
h
s/[][\\*.]/\\$/g
x
s/^\.XX//
x
s/^\\\.XX\(.*\)$/^\\.XX \pp/
G
s/\n//
'
输出偶数行
sed -n 'n;p' file

输出奇数行
sed -n 'p;n' file

倒序输出
sed '1!G;h;$!d' file
其中的限定符:
1表示第一行,$表示最后一行
关于!的解释:
After the address (or address-range), and before the command,
a ! may be inserted, which specifies that the command shall
only be executed if the address (or address-range)
  1. 实例

在testfile文件的第四行后添加一行,并将结果输出到标准输出,在命令行提示符下输入如下命令:

sed

将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除!

nl /etc/passwd | sed '2,5d'

只要删除第 2 行

nl /etc/passwd | sed '2d'

要删除第 3 到最后一行

nl /etc/passwd | sed '3,$d'

在第二行后(在第三行)加上“drink tea?”字样

nl /etc/passwd | sed '2a drink tea'

在第二行前插入

nl /etc/passwd | sed '2i drink tea'

如果是要增加两行以上,在第二行后面加入两行字,例如 Drink tea or … 与 drink beer?

nl /etc/passwd | sed '2a Drink tea or ......\
> drink beer ?'

将第2-5行的内容取代成为“No 2-5 number”

nl /etc/passwd | sed '2,5c No 2-5 number'

打印5-7行

nl /etc/passwd | sed -n '5,7p'

打印日志文件中时间戳“2019-08-18 15:11:08”开始到“2019-08-18 15:12:08”结束的行

sed -n '/2019-08-18 15:11:08/,/2019-08-18 15:12:08/p' log.txt
即打印行从第一个“2019-08-18 15:11:08 ......” 开始,到第一个“2019-08-18 15:12:08 ......”结束。

搜索 /etc/passwd有root关键字的行

nl /etc/passwd | sed -n '/root/p'

删除/etc/passwd所有包含root的行,其他行输出

nl /etc/passwd | sed  '/root/d'

搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行:

nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p;q}'

sed的搜索替换与vim/vi中的搜索替换功能很类似,都形如:

sed 's/要被取代的字串/新的字串/g'

/sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g' | sed 's/Bcast.*$//g'

一条sed命令,删除/etc/passwd第三行到末尾的数据,​​并​​把bash替换为blueshell

nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/'

直接修改文件内容

afile 内每一行结尾若为 . 则换成 !
sed -i 's/\.$/\!/g' afile

在 afile 最后一行加入 # This is a tes
sed -i '$a
  1. sed中正则表达式元字符

元字符中需要注意转义的字符

元字符

需要转义的形式

{ }

\ { n, m \ }

()

\ ( \ )

  1. 总结

sed擅长以非交互的方式处理文件,尤其擅长处理大文件,而且长于以行为单位处理文本。


awk

sed与awk_sed_04

  • BEGIN{ 这里面放的是执行前的语句 } — 对应 “开始”
  • END {这里面放的是处理完所有的行后要执行的语句 } — 对应 “结束”
  • {这里面放的是处理每一行时要执行的语句} —对应每一行的 “输入”

官方手册
​​​ http://www.gnu.org/software/gawk/manual/gawk.html​

  1. 语法
awk [-v var=value[-F..]] 'pattern {action}' var=value file(s)

awk [-v var=value[-F ..] -f scriptfile var=value file(s)

选项参数说明:

  • -F fs or --field-separator fs
    指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
  • -v var=value or --asign var=value
    赋值一个用户定义变量。
  • -f scripfile or --file scriptfile
    从脚本文件中读取awk命令。
  • -mf nnn and -mr nnn
    对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
  • -W compact or --compat, -W traditional or --traditional
    在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
  • -W copyleft or --copyleft, -W copyright or --copyright
    打印简短的版权信息。
  • -W help or --help, -W usage or --usage
    打印全部awk选项和每个选项的简短说明。
  • -W lint or --lint
    打印不能向传统unix平台移植的结构的警告。
  • -W lint-old or --lint-old
    打印关于不能向传统unix平台移植的结构的警告。
  • -W posix
    打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符=不能代替=;fflush无效。
  • -W re-interval or --re-inerval
    允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
  • -W source program-text or --source program-text
    使用program-text作为源代码,可与-f命令混用。
  • -W version or --version
    打印bug报告信息的版本。
  1. 基本用法
  • 用法一
awk '{[pattern] action}' {filenames}   # 行匹配语句 awk '' 只能用单引号

# 每行按空格或TAB分割,输出文本中的1、4列
$ awk '{print $1,$4}' log.txt

# 格式化输出
$ awk '{printf "%-8s %-10s\n",$1,$4}'
  • 用法二
awk -F  #-F相当于内置变量FS, 指定分割字符

# 使用","分割
$ awk -F, '{print $1,$2}' log.txt

# 或者使用内建变量
$ awk 'BEGIN{FS=","} {print $1,$2}' log.txt

# 使用多个分隔符。先使用空格分割,然后对分割结果再使用","分割
$ awk -F '[ ,]' '{print $1,$2,$5}' log.txt
多个分割符还可以如下定义:
[ \t,:]
  • 用法三
awk -v  # 设置变量

$ awk -va=1 '{print $1,$1+a}' log.txt
$ awk -va=1 -vb=s '{print $1,$1+a,$1b}'
  • 用法四
# 将awk脚本放入文件
$ awk
  1. 运算符

运算符

描述

= += -= *= /= %= ^= **=

赋值

?:

条件运算符

││

逻辑或

&&

逻辑与

~ 和 !~

匹配正则表达式和不匹配正则表达式

< <= > >= != ==

关系运算符

空格

连接

+ -

加,减

* / %

乘,除与求余

+ - !

一元加,减和逻辑非

^ ***

求幂

++ –

增加或减少,作为前缀或后缀

$

字段引用

in

数组成员

过滤第一列大于2的行
$ awk '$1>2' log.txt

过滤第一列等于2的行
$ awk '$1==2 {print $1,$3}' log.txt

过滤第一列大于2并且第二列等于'Are'的行
$ awk '$1>2 && $2=="Are" {print $1,$2,$3}'
  1. 内置变量

变量

描述

$n

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

$0

完整的输入记录

ARGC

命令行参数的数目

ARGIND

命令行中当前文件的位置(从0开始算)

ARGV

包含命令行参数的数组

CONVFMT

数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组

ERRNO

最后一个系统错误的描述

FIELDWIDTHS

字段宽度列表(用空格键分隔)

FILENAME

当前文件名

FNR

各文件分别计数的行号

FS

字段分隔符(默认是任何空格)

IGNORECASE

如果为真,则进行忽略大小写的匹配

NF

一条记录的字段的数目

NR

已经读出的记录数,就是行号,从1开始

OFMT

数字的输出格式(默认值是%.6g)

OFS

输出记录分隔符(输出换行符),输出时用指定的符号代替换行符

ORS

输出记录分隔符(默认值是一个换行符)

RLENGTH

由match函数所匹配的字符串的长度

RS

记录分隔符(默认是一个换行符)

RSTART

由match函数所匹配的字符串的第一个位置

SUBSEP

数组下标分隔符(默认值是/034)

# 输出顺序号 NR, 匹配文本行号
$ awk '{print NR,FNR,$1,$2,$3}' log.txt

# 指定输出分割符
$ awk '{print $1,$2,$5}' OFS=" $ "
  1. 正则表达式应用
# 输出第二列包含 "th",并打印第二列与第四列
$ awk '$2 ~ /th/ {print $2,$4}' log.txt
~ 表示正则匹配开始。// 中是正则表达式。

# 输出包含"abc"的行
$ awk '/abc/' log.txt

# 输出不包含"abc"的行
$ awk '!/abc/' log.txt

# 不包含abc的单词的行
$ awk '/\b((?!abc)\w)+\b/' log.txt

# 忽略大小写
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt

# 模式取反
$ awk '$2 !~ /th/ {print $2,$4}' log.txt
$ awk '!/th/ {print $2,$4}'
  1. 其他常见应用
# 计算文件大小
ls -l *.pl | awk '{sum+=$5} END {print sum}'

#使用内置函数
$ awk 'BEGIN{info="this is a test2012test!";print match(info,/[0-9]+/)?"ok":"no found";}'
  1. 总结

awk善于将一行文本按照列来进行处理。