一 . sed 简介 1 . 功能 sed 是一种流编辑器,所谓流编辑器是指能够对来自文件或者管道的输入流进行基本的文本转换的工具,比方说查找替换删除等。 2 . 最简单的运作机制 sed 程序运行时,会读入脚本,然后把脚本作用在每一个输入行上。 sed 在每个执行周期(excution cycle)里完成以下任务: 1) 读取下一行,行计数器加 1 2) 执行脚本 3) 一旦控制转移到脚本末尾,自动输出并清除模式空间的内容,进入下一个执行周期 注: 1) sed 每次都是从输入流读取下一行 2) 读入一行都会删除结尾的换行符再放入模式空间 3) 输出模式空间内容时也会自动添加新行符 3 . 模式空间和保持空间(hold place) 模式空间就是一个数据缓冲区,特点是一旦控制到达脚本末尾,模式空间的内容会被自动清除。 保持空间也是一个数据缓冲区,其内容不会被自动清除,这非常有用。 模式空间与保持空间在 sed 程序开始之前初始化为空。 二 . sed 命令的定址 1 . 补充概念 1) 行计数器 已经从输入流读取的最后一行的行号,读入新行会递增 2) 美元符($) 输入流的最后一行的行号($的含义受-s选项影响) 2 . 定址 可以为sed脚本中每个指令指定一个条件,条件成立指令才能执行,无条件则直接执行。 条件分 "地址" 或 "地址范围" 两种。 地址有以下几种形式: NUMBER 表示 "行计数器为 NUMBER" 这个条件 $ 表示 "行计数器为输入流最后一行的行号" 这个条件 /REGEXP/ 表示 "模式空间某部分能匹配REGEXP" 这个条件 REGEXP是正则表达式,须放在两个分隔符(/)之间 欲匹配字面的/或者/,都要使用反斜杠(/)进行转义 REGEXP末尾的$代表模式空间的结尾 /%REGEXP% 表示 "模式空间某部分能匹配REGEXP" 这个条件 REGEXP是正则表达式,须放在/%与%之间 适用于欲匹配大量字面/的情况,可编免大量地转义/ 分隔符还可以换为其它字符 /REGEXP/I 或 /%REGEXP%I 表示 "模式空间某部分能不区分大小写地匹配REGEXP" 这个条件 REGEXP是正则表达式,在/REGEXP/或/%REGEXP%之后添加I表示不区分大小写 这是一个GNU扩展 /REGEXP/M 或 /%REGEXP%M 表示 "模式空间某部分能匹配REGEXP" 这个条件 但REGEXP开头的 ^ 将匹配换行符之前的空串,而结尾的 $ 将匹配换行符之后的空串 这是一个GNU扩展 地址范围通过在两个地址之间添加一个逗号(comma)表示 笼统地讲,地址范围就四种形式,分别是 1) 正则式,行号 2) 正则式,正则式 3) 行号,行号 4) 行号,正则式 其中的正则式可以有/REGEXP/ 或 /%REGEXP% 等多种形式,这里只采用/REGEXP/作为例子: /REGEXP/,NUMBER 这个地址范围按如下方法匹配:从匹配REGEXP的行(包括此行)开始,持续到第NUMBER行(包括此行)。 如果找不到匹配REGEXP的行,则该地址范围不匹配任何行。 若NUMBER小于或者等于第一个匹配REGEXP的行的行号,则该地址范围只匹配该行;若NUMBER大于$(输入流最后一行的行号),则该范围会一直包括到输入流的最后一行。 /REGEXP1/,/REGEXP2/ 这个地址范围按如下方法匹配:从匹配REGEXP1的行(包括此行)开始,持续到从该匹配行的下一行开始第一个匹配REGEXP2的行(包括此行)。 如果找不到匹配REGEXP1的行,则该地址范围不匹配任何行。 如果在匹配REGEXP1的行后找不到匹配REGEXP2的行,则该地址范围会一直包括到输入流的最后一行(含此行)。 NUMBER,/REGEXP/ 这个地址范围按如下方法匹配:从第NUMBER(>=1)行开始(包括此行),持续到从第NUMBER行的下一行开始第一个匹配REGEXP的行(包括此行)。 如果NUMBER是个无效的行,则该地址范围不包括任何行。 如果从第NUMBER行的下一行开始找不到匹配REGEXP的行,则该地址范围会一直包括到输入流的最后一行(含此行)。 NUMBER,NUMBER 这个地址范围按如下方法匹配:从第NUMBER1行(包括此行)开始,持续到第NUMBER2行(包括此行)。 如果NUMBER1是个无效的行,则该地址范围不包括任何行。 如果NUMBER2 <= NUMBER1 则该地址范围只包括第NUMBER1 行。 如果NUMBER1是个有效行,但NUMBER2 > $ ,那该地址范围将一直包括到输入流的最后一行(包括此行)。 此外GNU扩展还有四种特殊的地址范围表达方式,它们是 `0,/REGEXP/' 和`ADDR1,+N' 以及 `ADDR1,~N' 还有 `FIRST~STEP' 。 0,/REGEXP/ 地址范围使得REGEXP可以匹配第一行的内容 ADDR,+N 这个地址范围按如下方法匹配:从满足地址 ADDR 的行开始(含此行),一直到接下来的第 N 行(含此行),一共 N+1 行。 如果 ADDR 无效,则该地址范围不包括任何行。 如果 ADDR 可以满足,但 N 太大以至于超过了输入流的最后一行,则该地址范围将一直匹配到输入流的最后一行(含最后一行) ADDR,~N 这个地址范围按如下方法匹配:从满足地址 ADDR 的行开始(含此行),一直到该匹配行下面的第一个号行为 N 的倍数的行(含此行)。 如果 ADDR 无效,则该地址范围不包括任何行。 如果 ADDR 可以满足,但匹配 ADDR 的哪一行之后没有行号是 N 的倍数的行,则该地址范围将一直包括到输入流的最后一行(含最后一行)。 FIRST~STEP 这个地址范围按如下方法匹配:找到第FIRST行(含此行), 按步长 STEP 找到该行之后所有的行。 如果FIRST 无效,则该地址范围不包括任何行。 如果在地址或者地址范围之后添加感叹号(!)则表示与不加感叹号相反的条件,例如$!表示"当前行计数器不是输入流最后一行的行号"这个条件。 三 . 替换命令 替换命令的形式为: s/REGEXP/REPLACEMENT/FLAGS 替换(substitude)命令的基本功能是在模式空间(pattern space)寻找匹配正则表达式REGEXP的部分,并替换成REPLACEMENT。 1 . FLAGS 只能是以下选项(option) g 指示 sed 将模式空间中匹配REGEXP的所有位置都替换成REPLACEMENT NUMBERth 指示 sed 只将模式空间中匹配REGEXP的第 NUMBERth 个位置替换成REPLACEMENT p 指示 sed 在完成模式空间的替换之后打印模式空间的内容到标准输出,注意,如果没有发生替换,那么p 命令不执行。 w FILENAME 指示 sed 在完成模式空间的替换之后打印模式空间的内容到文件 FILENAME ,注意,如果没有发生替换,那么w 命令不执行。 FILENAME 支持两个特殊的文件名 /dev/stderr 和 /dev/stdout 分别代表标准出错和标准输出,这是一个GNU扩展。 e 指示 sed 在完成模式空间的替换之后,把模式空间的内容作为命令执行,并把执行的结果写到模式空间中。这是一个GNU扩展功能。 i 或 I 指示 sed 在匹配REGEXP的时候忽略大小写。这是一个GNU扩展功能。 m 或 M 指示 sed 在匹配REGEXP的时候,用REGEXP首部的 ^ 匹配新行符之前的空串,用尾部的 $ 匹配新行符之后的空串。这是一个GNU扩展功能。 2 . REPLACEMENT REPLACEMENT不是正则表达式,但是,在REPLACEMENT中出现的一些字符是有特殊含义的: 1) & 代表模式空间中匹配REGEXP的部分,因此要在REPLACEMENT中表达字面&,需要用反斜杠转义 2) /number 是匹配REGEXP中第 number 对 /( 和 /) 之间的正则式的那部分字串。 3 . REGEXP REGEXP 是正则式,如果想表达字面意义的字符,其中需要转义的有: 1) 正则表达式的元字符 2) 斜杠(/),因为 sed 的 s 命令认为正则表达式REGEXP应该夹在两个斜杠之间(/REGEXP/) 四 . 常用的 sed 指令 q 功能: 1) 将控制转移到最后一条命令的后面 注意由于控制转移到最后一条命令的后面,可能会有自动输出。 n 功能: 1) 先输出模式空间内容(前提:自动输出没有被屏蔽) 2) 读入下一行,覆盖模式空间,行计数器增 1 3) 控制转移到下一条指令继续执行。 p 功能: 1) 输出模式空间内容 2) 控制转移到下一条指令 d 功能: 1) 立刻清除模式空间内容 2) 把控制转移到下一个周期的开始处继续执行 N 功能: 1) 在当前模式空间内容之后添加新行符,然后读入下一行,添在新行符之后,行计数器增1 2) 控制转移到下一条指令继续执行 P 功能: 1) 输出模式空间左数第一个新行符前面的所有字符,以及该新行符 2) 控制转移到下一条指令并继续执行 D 功能: 1) 清除模式空间里左数第一个新行符以及之前的所有字符 2) 如果清除过后模式空间不空,则控制转移到下一个周期且不再读入新行;否则控制转移到下一个周期的开始处(这样会读入新行)。 = 功能: 1) 输出行计数器的值并输出新行符 这是一个GNU扩展 { COMMANDS } 功能: 1) 把一组命令括在 { 和 } 之间,以便在某个条件下执行一组命令 y/CHAR_SET1/CHAR_SET2/ 把模式空间中的包含在CHAR_SET1中的字符改为CHAR_SET2中对应的字符 a/ TEXT 功能: 指出在周期末尾,自动输出模式空间之后,把文本TEXT也输出到标准输出 约束: 1) a 与 / 之间可以有 0 或以上的空格 2) TEXT 中的每一行,除了最后一行,都要以反斜杠结尾以转义新行符 3) 可以接受地址范围,或者单独的地址作为执行条件 GNU扩展: 如果a之后的字符中有非空格字符,则从a之后第一个非空格字符开始的串会被作为TEXT的第一行 如果第一行也是最后一行,则末尾无需加反斜杠以转义新行符 i/ TEXT 功能: 立即把文本TEXT输出到标准输出 约束: 1) i 与 / 之间可以有 0 或以上的空格 2) TEXT 中的每一行,除了最后一行,都要以反斜杠结尾以转义新行符 3) 只能接受地址范围作为执行条件 GNU扩展: 如果i之后的字符中有非空格字符,则从i之后第一个非空格字符开始的串会被作为TEXT的第一行 如果第一行也是最后一行,则末尾无需加反斜杠以转义新行符 r FILENAME 功能: 每个周期的自动输出之前,把文件FILENAME的内容插入到输出流并输出。 如果FILENAME无法被读取,则sed认为它是一个空文件,无错误提示。 GNU扩展: 特殊串 /dev/stdin 被认为是标准输入 w FILENAME 功能: 将模式空间的内容写入文件FILENAME GNU扩展: 1) 特殊串/dev/stdout 和 /dev/stderr 分别表示标准输出和标准出错 五 . 模式空间与保持空间的互动 h 把模式空间的内容拷贝到保持空间 H 在保持空间内容末尾添加新行符,并把模式空间的内容拷贝到新行符之后 g 把保持空间的内容拷贝到模式空间 G 在模式空间的内容之后添加新行符,并把保持空间的内容拷贝到新行符之后 x 交换模式空间与保持空间的内容 六 . sed 的选项 前面讲解过 sed 的执行周期,我们知道,sed 每次从输入流读入一行,然后运行脚本,周而复始,直到读入完毕。 -e 选项和 -f 选项 -s 选项涉及到脚本和输入流的获取: -e SCRIPT SCRIPT 是要在 sed 程序中执行的指令,sed 会把这些指令添加到指令序列之后 -f SCRIPT_FILE SCRIPT_FILE 中存放着要在 sed 程序中执行的指令,sed 会把这些指令添加到指令序列之后 -s -s 是一个 GNU 扩展 当命令行中出现多个输入文件时,sed 默认会把所有文件的顺序拼接作为一个输入流,在这种情况下,美元符号($)会被认为是这个输入流的最后一行,而地址范围也可以跨越多个文件。如果想把命令的作用范围限制在一个文件之内,则可以使用 -s 选项,此时,美元符($)就代表一个文件的结尾了,而行号则是相对于每个文件开头的行数。 -n 前面讲过,控制转移到脚本之后时,sed会自动输出并清除模式空间的内容,-n选项能屏蔽这个动作: 七 . sed 的分支命令 : LABEL 用于在 sed 程序中设置一个标识位 b LABEL 无条件将控制跳转到(branch to分支到) LABEL 这个标识 如果不指定 LABEL,则控制转移到脚本之后。 因此无LABEL的b导致: 1) 如果自动输出没有被屏蔽,则输出模式空间内容 2) 进入下一个执行周期 t LABEL 当 sed 的上一个替换命令(s)成功发生替换时,跳转到 LABEL 这个标识 如果不指定 LABEL,则控制跳转到本周期末尾。 因此无LABEL的t导致: 1) 如果自动输出没有被屏蔽,则输出模式空间内容 2) 进入下一个执行周期
八. sed 实践
1. unix 文本文件转换为 windows 格式文件
sed 's/$/\r/' unix.txt > win.txt
2.