GNU sed 4.5 版参考文档全文翻译 各命令和随带20个示例详细解析(五)

12 篇文章 2 订阅

GNU sed 一个流编辑器(五)

—— 版本 4.5,2018年3月30日

作者:Ken Pizzini, Paolo Bonzini
译者:浙江省杭州市 Samuel        

标签:Linux sed 4.5版本 帮助文档 参考文档 全文翻译 随带20个示例 详细解析

版权声明:本文为博主原创译文,未经博主允许不得转载。https://blog.csdn.net/qq_39785418/article/details/89968486

5、 正则表达式:选择文本

5.6 正则表达式扩展

  在4.3节和s命令的正则表达式中,下面的序列都具有特殊的含义。

  它们可以用在基本(5.3节)和扩展(5.4节)正则表达式中,无论是否使用-E或-r选项。


\w			匹配任意组成“单词”的字符。组成“单词”的字符是任意字母、数字或下划线(_)。
			$ echo "abc %-= def." | sed 's/\w/X/g'
			XXX %-= XXX.
			
\W			匹配任意“非单词”字符。
			$ echo "abc %-= def." | sed 's/\W/X/g'
			abcXXXXXdefX
			
\b			匹配单词边界;也就是说,如果左边的字符是“单词”字符,右边的字符是“非单词”字符,则就会匹配;或者反之亦然。
			$ echo "abc %-= def." | sed 's/\b/X/g'
			XabcX %-= XdefX.
			
\B			匹配单词边界以外的任何位置,如果左边的字符和右边的字符都是“单词”字符,或者都是“非单词”字符,则会匹配。
			echo "abc %-= def." | sed 's/\B/X/g'
			aXbXc X%X-X=X dXeXf.X
			
\s			匹配空白字符(空格和各种tab制表符)。内嵌在模式空间和保持空间的换行符也会匹配。
			echo "abc %-= def." | sed 's/\s/X/g'
			abcX%-=Xdef.
			
\S			匹配非空白字符。
			echo "abc %-= def." | sed 's/\S/X/g'
			XXX XXX XXXX
			
\<			匹配一个单词的开始位置。
			echo "abc %-= def." | sed 's/\</X/g'
			Xabc %-= Xdef.
			
\>			匹配一个单词的结束位置。
			echo "abc %-= def." | sed 's/\>/X/g'
			abcX %-= defX.
			
\‘			只匹配模式空间的开始位置。这与多行模式的^不同。

			比较以下两个例子:
			printf "a\nb\nc\n" | sed 'N;N;s/^/X/gm'
			Xa
			Xb
			Xc
			
			# 译者:反斜杠后面的字符是通过按键1左边的那个键实现的。
			printf "a\nb\nc\n" | sed 'N;N;s/\`/X/gm'
			Xa
			b
			c
			
\’			只匹配模式空间的开始位置。这与多行模式的“^”不同。(译者:反斜杠后面的字符不知如何输入?那个键?这里复制原文而来)
			printf "a\nb\nc\n" | sed 'N;N;s/$/X/gm' 
			aX
			bX
			cX
			
			# 实验时发现有趣的现象
			
			printf "aAAA\nb\nc\n" | sed 'N;N;s/\|/X/gm'
			(printf "aAAA\nb\nc\n" | sed -E 'N;N;s/|/X/gm')一样的结果:
			XaXAXAXAX
			XbX
			XcX

5.7 反向引用和子表达式

  反向引用是正则表达式的命令,它引用前面被正则表达式匹配的一部分。反向引用由反斜杠和一个数字(例如“\1”)组成。被引用的部分是通过使用左右圆括号包围的正则表达式匹配部分,这部分正则表达式称为子表达式。

  反向引用和子表达式可用于两种情形:一是在正则表达式搜索模式内;二是在s命令替换内容中(参见4.3节[正则表达式地址]和3.3节[s命令])。

  在正则表达式搜索模式中,反向引用用于匹配与前面匹配的子表达式相同的内容。在下面的例子中,子表达式是“.”(句点),它代表任意单个字符,是通过使用圆括号包围使其成为子表达式。反向引用“\1”要求匹配与子表达式相同的内容(即相同的字符)。

  下面的命令匹配三个字符组成的单词,中间字母是o,开头和结尾字符一样。

$ sed -E -n '/^(.)o\1$/p' /usr/share/dict/words 
bob
mom
non
-o-
pop
......

  根据左圆括号的位置,从左到右对多个子表达式自动编号。此命令搜索由6个字母组成的回文,即:前3个字母分别是任意单个字符,使用圆括号使之成为3个子表达式,后跟是3个逆序的反向引用):

$ sed -E -n '/^(.)(.)(.)\3\2\1$/p' /usr/share/dict/words 
AAAAAA
degged
denned
hallah
kakkak
mallam
marram
......

  在s命令中,反向引用可用于替换部分中,用于引用正则表达式(regexp)的子表达式。

  下面的例子在正则表达式中使用两个子表达式来匹配两个空格分隔的单词。在替换部分中使用反向引用,以不同的次序打印这些单词。

$ echo "James Bond" | sed -E 's/(.*) (.*)/The name is \2, \1 \2./'
The name is Bond, James Bond.

  当使用字符“|”进行两选一时,如果反向引用的组不参与匹配,则会使整个匹配失败。例如,“a(.)|b\1”不会匹配ba。当使用-e或-f文件,给定多个正则表达式时,每个表达式的反向引用都是本地的。

  译者自己试验:

$ echo ba | sed -E -n '/a(.)|b\1/p'       #没有输出
$ echo ab | sed -E -n '/a(.)|b\1/p'
ab
$ echo ccc | sed -E -n '/a(.)|b\1/p'       #没有输出

5.8 转义序列——指定特殊字符

  在这一章节之前,我们只遇到了“^”这样形式的转义,它告诉sed不要把脱字符解释为一个特殊的字符,而是从字面上去理解它。例如,“*”匹配一个星号,而不是零个或多个反斜杠。

  本章介绍另一种转义——即应用于通常按字面上理解的字符或字符序列的转义,并且sed用特殊字符进行替换。这提供了一种以可视的方式在模式中编码不可打印字符的方法。sed脚本中非打印字符的外观没有限制,但是当在shell中编写脚本或文本编辑时,使用以下转义序列之一通常比使用它所表示的二进制字符更容易:(除了“\n”这个例外,这里介绍的所有转义符都是GNU扩展。在基础正则表达式模式中,设置POSIXLY_CORRECT可以在方括号表达式中禁用它们。)

  这些转义列表是:


\a			生成或匹配一个BEL字符,这是一个“警告”(alert)(ASCII 7)。

\f			生成或匹配一个换页符(ASCII 12)。

\n			生成或匹配一个换行符(ASCII 10)。

\r			生成或匹配一个回车符(ASCII 13)。

\t			生成或匹配一个垂直tab制表符(ASCII 9)。

\cx			生成或匹配CONTROL-x,x是一个任意字符。\cx的精确效果如下:如果x是一个小写字母,它会被转成大写;然后反转字符的
			第6位变成十六进制40。因此,\cz变成了十六进制1A,但是 \c{变成了十六进制3B,而 \c; 变成了十六进制7B。
			
\dxxx		生成或匹配其十进制ASCII值为xxx的字符。

\oxxx		生成或匹配其八进制ASCII值为xxx的字符。

\xxx		生成或匹配其十六进制ASCII值为xxx的字符。

  \b(backspace回退)转义被忽略,因为与现有的“单词边界”意思相冲突。

5.8.1 转义优先级

  GNU sed先处理转义序列,然后将文本传递到s///命令和地址匹配的正则表达式。因此,以下两个命令是等效的(“0x5e”是字符“^”的十六进制ASCII值):

$ echo 'a^c' | sed 's/^/b/'
ba^c
$ echo 'a^c' | sed 's/\x5e/b/'
ba^c

  如下所示(“0x5b”,“0x5d”分别是“[”,“]”的十六进制ASCII值):

$ echo abc | sed 's/[a]/x/'
Xbc
$ echo abc | sed 's/\x5ba\x5d/x/'
Xbc

  但是,由于会出现意外的边缘案例,建议避免使用此类特殊字符。例如,以下内容不等效:

$ echo 'a^c' | sed 's/\^/b/'
abc
$ echo 'a^c' | sed 's/\\\x5e/b/'
a^c

5.9 处理多字节字符和语言环境设置注意事项

  GNU sed能在多字节区域(例如UTF-8)中处理有效的多字节字符。(一些regexp边界用例依赖于操作系统和libc的实现。所示的示例可以在使用glibc的GNU/Linux系统上正常工作。)

  下面的示例使用希腊字母大写Sigma(∑,Unicode码位0x03A3)。在UTF-8语言环境中,sed能正确地将sigma处理为一个字符,尽管它是2个八位字节:

$ locale | grep LANG
LANG=en_US.UTF-8
$ printf 'a\u03A3b'
aΣb
$ printf 'a\u03A3b' | sed 's/./X/g'
XXX
$ printf 'a\u03A3b' | od -tx1 -An
61 ce a3 62

  为了强制sed单独处理八位字节,请使用C语言环境(也称为POSIX语言环境):

$ printf 'a\u03A3b' | LC_ALL=C sed 's/./X/g'
XXXX
5.9.1 无效的多字节字符

  sed的正则表达式在多字节语言环境中不能匹配无效的多字节序列。

  在下面的示例中,ascii值为0xCE是一个不完整的多字节字符,(这里显示为Ⓧ,在译者的实际测试中没有任何显示!)。正则表达式中句点“.”不能匹配它:

$ printf 'a\xCEb\n'
aⓍ×e
$ printf 'a\xCEb\n' | sed 's/./X/g'
XⓍ×X
$ printf 'a\xCEc\n' | sed 's/./X/g' | od -tx1c -An
58  ce  58  0a
X       X  \n

  (但是在我的测试是这样的,与上面不一样:

$ printf  'a\xCEb\n'
a
$ printf 'a\xCEb\n' | sed 's/./X/g'
X
printf 'a\xCEb\n' | sed 's/./X/g' | od -tx1c -An
58  ce  58  0a
X 316   X  \n

  )
  类似地,这个“能抓住所有的”正则表达式 “.*” 不能匹配该整行:(我的测试结果也不一样,具体不记录了。)

$ printf 'a\xCEc\n' | sed 's/.*//' | od -tx1c -An
ce  63  0a
c  \n

  GNU sed提供了特殊的z命令来清除当前模式空间,而不管多字节字符是否无效,它的工作方式类似于s/.*//,但也会删除无效的多字节字符。

$ printf 'a\xCEc\n' | sed 'z' | od -tx1c -An
0a
\n

  或者,强制在C语言环境下分别处理每个八位字节(C语言环境中每个八位字节是的有效字符):

$ printf 'a\xCEc\n' | LC_ALL=C sed 's/.*//' | od -tx1c -An
0a
\n

  sed不能处理无效多字节字符的特性可以用于诊断一个文件中是否有这样无效序列。下面的示例中,\xCE\xCE是一个无效的多字节序列,而\xCE\A3是一个希腊Σ字符有效的多字节序列。

  下面的sed程序先使用s/.//g命令移除所有有效的字符,然后使用H命令,把模式空间中遗留的内容——即遗留的无效字符追加到保持空间中,程序执行最后输入行($可以引用)时,通过x命令重新获取保持空间的内容(译者:保持空间内容转到模式空间),使用s/\n//g命令移除换行符,再利用l命令(用明确可视的形式)打印所有遗留的八位字节的内容。因此,任何无效的多字节序列都打印为八进制值:

  (译者:测试结果与原文有一些不同,有部分测试内容是我加入的。)

$ printf 'ab\nc\n\xCE\xCEde\n\xCE\xA3f\n' > invalid.txt
$ cat invalid.txt 
ab
c
               # 原文中有:Ⓧ×Ⓧ×de,而我的测试是空行!
 Σf
$ sed -n 's/.//g; H; ${x;s/\n//g;l}' invalid.txt 
\316\316$

  再使用多几个命令,sed可以打印与每个无效字符(第3行)对应的准确行号。然后,通过强制使用C语言环境并使用八进制转义序列来删除这些字符:

$ sed -n 's/.//g; = ;l' invalid.txt 
1
$              # 这是l命令执行显示而来,$表示行尾,说明打印是空行。
2
$
3
\316\316$
4
$

$ sed -n 's/.//g;=;l' invalid.txt | paste - - 
1       $
2       $
3       \316\316$
4       $

$ sed -n 's/.//g;=;l' invalid.txt | paste - - | awk '$2!="$"'
3       \316\316$

$ LC_ALL=C sed '3s/\o316\o316//' invalid.txt > fixed.txt
$ cat fixed.txt 
ab
c
de
Σf
5.9.2 大小写转换

  GNU sed的替换命令(s)支持使用\U、\L代码进行大小写转换。这种大小写转换支持多字节字符:

$ printf 'ABC\u03a3\n'
ABCΣ

$ printf 'ABC\u03a3\n' | sed 's/.*/\L&/'    # &引用匹配的全部
abcσ
5.9.3 多字节正则表达式字符类

  在其他的一些语言环境,如果没有指定排序方式,那么,‘[a-d]’可能等价于‘[abcd]’或者‘[aBbCcDd]’,它可能无法匹配任何字符,或者它匹配的字符集甚至可能是不稳定。要获得方括号表达式的传统解释,可以通过将LC_ALL环境变量设置为“C”值来使用“C”语言环境。

# 备忘录:是否有一个真实的系统或者执行环境让‘-’替换‘A’?
$ echo A | sed 's/[a-z]/-/'
A

  它们的解释取决于LC_CTYPE环境设置;例如,“[[:alnum:]]”表示当前区域环境中数字和字母的字符类。

# 备忘录:这适用于glibc系统,而不是musl-libc/freebsd/macosx。
$ printf  'clich\n' | LC_ALL=fr_FR.utf8 sed 's/[[=e=]]/X/g'
clichX           # 我的测试结果是:clich

[GNU sed 4.5 版参考文档全文翻译 各命令和随带20个示例详细解析(六)] (https://blog.csdn.net/qq_39785418/article/details/90032442)

  如果您觉得译文对您有帮助,不妨给个  微信打赏   翻译不易,各位的支持,能激发和鼓励我更大的热情。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值