sed与awk
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sed与awk相关的知识,希望对你有一定的参考价值。
sed
- 命令格式
- 基本命令
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, 2, 3,...),表示替换第几个匹配的内容。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
命令集的多个命令也可以在命令行中使用;连接使用。
- 改变控制流顺序
- sed的正常控制流
- 步骤1到步骤4,周而复始。
- 处理多行模式空间(N、D、P)
多行模式空间:
单行模式命令 | 解释 | 多行模式命令 | 解释 |
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 | 交换保持空间和模式空间的内容。 |
命令(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)
- 实例
在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
- sed中正则表达式元字符
元字符中需要注意转义的字符
元字符 | 需要转义的形式 |
| \\ n, m \\ |
() | \\ ( \\ ) |
- 总结
sed擅长以非交互的方式处理文件,尤其擅长处理大文件,而且长于以行为单位处理文本。
awk
- BEGIN 这里面放的是执行前的语句 — 对应 “开始”
- END 这里面放的是处理完所有的行后要执行的语句 — 对应 “结束”
- 这里面放的是处理每一行时要执行的语句 —对应每一行的 “输入”
官方手册
http://www.gnu.org/software/gawk/manual/gawk.html
- 语法
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报告信息的版本。
- 基本用法
- 用法一
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 BEGINFS="," 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
- 运算符
运算符 | 描述 |
= += -= *= /= %= ^= **= | 赋值 |
?: | 条件运算符 |
││ | 逻辑或 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ – | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
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
- 内置变量
变量 | 描述 |
$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=" $ "
- 正则表达式应用
# 输出第二列包含 "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 BEGINIGNORECASE=1 /this/ log.txt
# 模式取反
$ awk $2 !~ /th/ print $2,$4 log.txt
$ awk !/th/ print $2,$4
- 其他常见应用
# 计算文件大小
ls -l *.pl | awk sum+=$5 END print sum
#使用内置函数
$ awk BEGINinfo="this is a test2012test!";print match(info,/[0-9]+/)?"ok":"no found";
- 总结
awk善于将一行文本按照列来进行处理。
以上是关于sed与awk的主要内容,如果未能解决你的问题,请参考以下文章