再谈 linux 的sed用法

很多东西, 如果太复杂, 太庞杂, 一开始, 可以只掌握最简单的. 如果连最简单的都不能掌握, 那看那么多有什么用?


关于cut, sed的 处理过程和思想?


vm: virtual machine, virtual memory: 虚拟机, 虚拟内存vm内存在windows中,叫做 pagefile.sys. 而在linux中叫做 swap.
vm虚拟内存是为了弥补真实内存设备/资源的不足而引入的. 为了防止"突然发生的" 交换页, 可以把虚拟内存设置大一点.


sed的处理执行过程:

  1. 是依次先读入行, 然后(如果有匹配模式表达式, 如果有编辑命令)则进行编辑命令处理, 然后将行中的内容

输出. 如果没有编辑命令, 即使有匹配模式表达式, 也会将没有被匹配到的行输出. (就是如果有匹配模式表

达式, 它只是对匹配到的这一行进行编辑命令处理, 而没有匹配到的行, 只是说, 不进行后面指定的编辑命令

的处理而已, 但是它仍然要输出)!
2. sed的s替换命令, old部分可以使用正则, 而new部分不可以使用正则.
3. sed的编辑命令 全都是 单字母命令, 如n就是其中的一个, 命令和命令之间要用分号隔开. 如果不分隔
,比如: sed 'np' foo , 会提示: sed: -e expression #1, char2: extra characters after command
4. 如果是多个命令, 最好 是用大括号{}把命令序列括起来. 当然不括起来也可以.
5. sed 的格式: sed [option] '{命令序列}' [input-files]
6. sed 的默认操作是 "output" 输出当前读入的行. 你可以用sed '' foo.来输出所有的行; 但是如果你用p
命令, 会将当前模式空间中的行重复输出, 结果得到两个相同的行.
7.


关于保持空间

模式空间中的内容, 是一次读入文件中的行, 当前行读入/处理/输出后, 读入下一行时, 当前行的内容将在 模式空间被 覆盖, 就像对变量的 再次 赋值一样. 所以 模式空间中的内容, 只是暂时存在的, 不是永久的, 所以, 模式空间, 也叫做 临时空间, 也叫做 暂存空间.

保持空间(hold space, 暂存区), 可以看作是仓库, 而模式空间, 可以看作是 车间. 为什么需要保存空间? 因为, 模式空间中的内容不能长期保存, 由时候, 在后面的输出中, 需要使用前面的某些行的内容, 这个时候, 就需要把前面的行的内容存储起来, 这个存储的地方就是这里的保持区. 保持区的操作有 : h, H, g, G , x


sed 的执行过程:
是 从文件中 依次读入行, 然后进行(命令/参数)处理(包括p打印命令), 然后 再将当前 模式空间中的内容 输出到屏幕上.
注意是先进行处理, 然后再输出 . 也就是说, 默认的 sed命令是 输出p. 或者这样理解, 在 sed的命令 序列中, 总是有一个 "p"命令 默认在 命令序列的 "最后"! 除非你显式的使用 选项 "-n" 来取消 命令序列的最后的'p'命令.


轻松写正则表达式
任意数量的任意字符 .*
指定字符的任意数量: a, b ,*等等
一个或多个任意字符 .+
表示开头/结尾位置 ^ $
存储子匹配, 后向引用 () 1 指导 99 ()是元字符, 表示分组, 要表示括号这个 普通含义 的字符, 需要使用 反写杠来表示 转义

**关于括号: 由于在替换时, 要替换的内容, 不能使用正则(反向引用除外), 所以 所有的括号, 包括大括号, 中小 括号都不用处理, 表示正常的括号. 而在 s命令的old部分, 要使用 正则表达式, 中的括号, 只有 中括号[ ] 可以不用加 反斜杠转义, 而其他小括号和 大括号都要 加反斜杠才正确! **

注意非 ^ 选择符的使用 这种写法有时候会收到 意想不到的好效果!!!
它是从字符串内容的 开头 开始检查匹配, 一旦发现 不符合匹配的话, 马上就终止检查. 不会再往后往下检查了, 马上就跳出检查了. 这个跟 什么贪婪匹配不同!
比如: 101, abc 要截取101, 就使用: sed 's/([^,]*).*/[1]/' foo


管道和重定向的区别?
管道是把 前面的输出 作为后面这个命令的输入 作为输入数据或内容进行处理, 后面跟的是 继续处理的 命令.
而重定向是把 它们(输出) 写入到一个 文件中, 后面跟的 是 "文件名"
------ 所以更多的时候, 是用的 管道 --------

理解 sed的! 命令

! 你可以认为是"取反, 取否", 但是不完全准确.
他表示 "对当前匹配行" 不执行!后面的命令, 而"对当前匹配行以外的其他行" 执行! 后面的命令.
比如: sed '/inet addr/ !d' foo.txt 即为: 匹配inet addr行不删除 , 而其他行都删除. 就只剩下 inet addr 这一行了.

在正则表达式中, 像空格字符不需要转义, 如果你分不清是否要 转义, 可以先不加反斜杠, 如果不行, 再加上反斜杠. 尝试一下就好了.


在sed命令中, 有多个命令, 如 a, c, i, r, q, w, hHgGx, s等多个命令, 其中最重要的命令当然还是 s.

a命令, i命令, 可以直接跟要插入的文本, 也可以为了区分和后面的内容, 加上反斜杠,
比如: sed 'aok' foo.txt 或者 sed 'iok ' 就等于: sed 'aok' foo.txt

在这里, 特别要主要 i和a的用法, 他表示sed 要在 某一行的前面或 后面插入文本行. 这个还是非常有用的, 因为有现成的i或a命令, 所以, 就不用再考虑使用 s替换命令了. 然而 使用a或i命令的时候, 为了将命令字符a或i跟实际插入的内容相区别, 需要在a或i的后面加上反斜杠. 但是在反斜杠后面就不能再加空格了, 否则空格会作为插入的字符内容一并记入其中. 除了在某一行的前面或后面插入文本行, 还可以在多行 范围内, 在多行中的每一行 的前面或后面插入 文本行. `sed -i '5,8iaaaa' ‵ 表示在5,8整个4行的每一行的前面都插入aaa. 其他同理, 参考: http://blog.csdn.net/zbszhangbosen/article/details/7434191

在 sed中, 在正则表达式中, 要删除整行, 使用d命令, 如果不是删除整行, 而是只是删除/增加 一行中 部分的内容, 那就是用 替换. 替换中,只要替换的内容为空, 就是删除!! 只要替换^就是增加!!!

空行的正则是: ^$, 如: sed 's/^$/d' foo.txt
在执行多个编辑命令的时候, 可以将多个命令分开, 这时候, 就已定要加 -e选项, 也可以将多个命令写在一起, 用分号分割, 这时候可以不用加 -e选项.
sed 's/#.*//; 中间可以有多个空格 ; /^$/d' foo.txt


终结: 关于模式匹配的种类: 贪婪模式, 懒惰模式, 侵占模式?

  1. 模式匹配有 可能分为多个 子模式 匹配, 只有当所有子模式 匹配都 成功的时候, 才会认为整个 模式匹配成功, 比如: .foo就是 子模式p1(.)和子模式p2(foo)组成的
  2. 所谓的匹配的种类, 都是针对 "可变的"量词 而言的, 包括: ?, *, +, {m, }, {m, n} 对于固定次数的量词 {m}则是没有这种说法的
  3. 贪婪模式是默认的匹配种类, 懒惰模式是在量词的后面加上 问号, 如: ??, *?, +? {m,n}? 而侵占模式是是在量词后面加上加号, 如: ?+, *+, {m, n}+

贪婪模式首先会匹配所有的字符, 看整体是否匹配, 如果不匹配, 则依次, 不断的吐出 最后的字符来匹配其他的子模式...直到最后....
侵占模式, 是首先尽可能匹配所有的字符, 而且, 不会吐出字符, 也不管其他子模式是否匹配. ...
懒惰模式, 也叫勉强模式, 是尽量匹配尽可能少 的字符....

参考:

所以, 有时候, 用+ 号可能 匹配不成功, 而用* 则匹配成功! 特别是用 * 号时, 要理解 AB , 前面的字符本身就不存在, 其本身就是任意字符的匹配情况, 如AB 可以匹配到 ACCCCB 的情况, 这里A* 就是(做没有A)的情况来匹配的, 实际匹配成功的只是因为B . 所以, 凡是AB 的情况, 可以不用管 A, A什么的, 只管 , 只看 后面的那个字符内容就可以了, 这里 只需要看B 就可以了!!!! 也就是, 不管B 前面是什么 都可以匹配到....


sed的处理执行过程:

  1. 是依次先读入行, 然后(如果有匹配模式表达式, 如果有编辑命令)则进行编辑命令处理, 然后将行中的内容输出. 如果没有编辑命令, 即使有匹配模式表达式, 也会将没有被匹配到的行输出. (就是如果有匹配模式表达式, 它只是对匹配到的这一行进行编辑命令处理, 而没有匹配到的行, 只是说, 不进行后面指定的编辑命令的处理而已, 但是它仍然要输出)!

  2. sed的s替换命令, old部分可以使用正则, 而new部分不可以使用正则.

  3. sed的编辑命令 全都是 单字母命令, 如n就是其中的一个, 命令和命令之间要用分号隔开. 如果不分隔,比如: sed 'np' foo , 会提示: sed: -e expression #1, char2: extra characters after command

  4. 如果是多个命令, 最好 是用大括号{}把命令序列括起来. 当然不括起来也可以.

  5. sed 的格式: sed [option] '{命令序列}' [input-files]

  6. sed 的默认操作是 "output" 输出当前读入的行. 你可以用sed '' foo.来输出所有的行; 但是如果你用p命令, 会将当前模式空间中的行重复输出, 结果得到两个相同的行.


掌握了sed命令后, 跟sed相似的awk命令也就很容易了. 他们的 命令格式和方法, 思想都差不多.

awk [options] 'commands' file-to-treated.
options 中 记住最常用的一个选项 -F 表示分割字段类型就好了.
commands的格式:

  1. 整个commands命令, 用单引号括起来, 而命令语句中的括号则必须用 双引号才行.
  2. 所有的命令语句类似C 语言. 而且都要放在 大括号中
  3. 关于BEGIN END, 很简单. 在awk中, BEGIN & END 都只执行一次. 他们不会对 "文件中按行处理 中的 行" 进行循环. 只有中间的代码才会 对文件中的所有行进行 循环处理.

比如: awk -F: 'BEGIN{print "aaa bbb ccc"} {print "$1 $2 $3";} END{print "end end end"}' /etc/passwd | head -n 5 或者 | tail -n5 注意经过head 和tail的裁剪后, begin和end输出的内容可以 被裁剪看不到了:


sed行的指定, 不但可以是数字, 还可以是正则表达式, Regexp总是以两个斜线为范围的

  1. 如果是范围, 则正则表达式总是第一个被匹配的行, 如sed '1, /^s/d' /etc/passwd 则表示第一行, 到第一个行首为s的行, 并不是所有的行, 要删除所有以s开头的行,应该是 sed '/^s/d' /etc/passwd
  2. sed中的&, 表示前面找到的部分.在色调的替换命令中, 使用:
    sed 's/[0-9]/&+num/g' ~/num

cat命令是打印吗?

  1. cat命令并不是打印命令, 而是连接, 真正的打印命令是print, 也不是type, type是表示类型.
  2. cat是连接多个文件的,(通常是cat 1个文件, 所以就常常误以为cat就是打印文件内容了, 实际上不是! ) 可以是多个输入文件, 如: cat file1 file2 file3. 最重要的是, 还可以是stdin 标准输入. 多行输入内容用 <<EOF EOF
  3. 但是标志开始和结束符号不一定必须使用eof, 可以是任意的字符串, 如: fo, foo, fooo, 等等
  4. 引导符号是 两个<<, 相当于输入重定向. 不是三个小于号.
  5. 要注意的是, cat默认的是输出到stdout, 屏幕上, 如果要重定向到修改后的文件里面, 需要在cat后使用 ">>"符号, 中间可以留有空格???

  1. sed的执行过程, 是以循环读取的每一行为单位, 先执行引号(通常是单引号)中的命令, 包括参数, 包括p命令,d命令等, 对模式空间的内容进行编辑处理, 然后再输出 模式空间的内容.

对模式空间的内容进行编辑, 包括模式空间和暂存空间中的内容之间的交换处理等. 处理完成后, 总是输出当前模式空间中的内容(除非你显式地指定-n 就不会输出.), 然后再扫描读入下一行的内容到模式空间, 然后处理, 然后输出, 然后不断循环知道文件的结尾.

  1. sed命令中的正则
    有两个, 一个是正则替换, 有三个斜杠, sed -i 's/some/other/g' filename , 另一个是使用正则表达式来匹配 行. 表示匹配行, 只有两个斜杠, 而且如果有起止范围的话, 只会匹配第一个匹配成功的行. sed -i '1,/^some/ d ' filename

  2. 关于sed中的全局替换/g?
    全局替换/g是一个标识, 它表示的是"在一行"内 . 因为sed的处理对象是 以 "行" 为单位的. /g是说, 在 "一行"内 , 如果有多个匹配的情况, 则全部替换, 否则如果没有/g标识, 则默认的值替换第一个 匹配到的情况.

  1. 关于 sed '/ccc/{x;p;x;}' file
    其中的 /ccc/ 表示的匹配ccc的这一行
    x表示的是, 将模式空间的内容和暂存空间中的内容进行互换(模式空间和暂存空间实际上都是一段内存buffer而已), 这时候模式空间中的内容就是暂存空间中的内容了, 执行p命令,就输出了暂存空间中的内容了, 然后再执行x, 再进行一次替换, 就把原来的模式空间中的内容替换回来了. 这个后面就不用p命令了, 因为执行完单引号中的命令后, 还有一个默认的输出命令, 所以, 这时候, 模式空间中的内容就会被输出.

因此, x;p;x 命令就是把当前暂存空间中的内容和当前行的内容 依次 输出来.


miscellaneous杂项

sed的格式: sed [options] '{command/edit}' parameters.

sed在临时缓冲区(模式空间) 对文件进行处理, 所以不会修改原文件, 除非显式的指明-i选项. 前者相当于一个字符串拷贝, 后者则是一个字符串地址引用, 修改的就是这个字符串本身.

wc命令, 就是"word count", 单词计数, 实际上还是很好用的, -l: --line, 统计行数, -w: --word 统计单词个数. -c --char 统计字符数.

shell变量的类型:

  1. 系统预先定义的变量, 通常是大写的, 如: PATH, USER, HOME, LANG(注意这里不是language).
  2. 用户自己定义的变量(没有用export关键字的), 叫本地local variables, 本地变量.
  3. 用户自己定义的, 而且用export修饰的, 叫environment 环境变量, 可以在 subshell中使用的.

理解shell解释器解释命令的方式, 它是用空格做分隔符的. 所以在shell命令行中, 空格不是任意添加或不加的, 比如在变量赋值时, 等号两边不能有空格, 而用test或 其别名 "[" 判断时则要添加空格!

原文地址:https://www.cnblogs.com/bkylee/p/6828865.html