Linux Sed   

Linux sed command

1. sed 介绍

http://blog.chinaunix.net/uid-26805356-id-4088668.html
http://www.cnblogs.com/edwardlost/archive/2010/09/17/1829145.html

sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。 sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。

2. 定址

定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。

地址是一个数字,则表示行号;是“$”符号,则表示最后一行。例如:

sed -n '3p' datafile
只打印第三行

只显示指定行范围的文件内容,例如:

# 只查看文件的第100行到第200行
sed -n '100,200p' mysql_slow_query.log

地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。例如:

sed '2,5d' datafile
#删除第二到第五行
sed '/My/,/You/d' datafile
#删除包含"My"的行到包含"You"的行之间的行
sed '/My/,10d' datafile
#删除包含"My"的行到第十行的内容

3 命令与选项

sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行

sed不向grep一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。

3.1 命令

 a\	 在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行

 c\	 用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行
 i\	 在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行
 d	 删除行
 h	 把模式空间里的内容复制到暂存缓冲区
 H	 把模式空间里的内容追加到暂存缓冲区
 g	 把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容
 G	 把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面
 l	 列出非打印字符
 p	 打印行
 n	 读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理
 q	 结束或退出sed
 r	 从文件中读取输入行
 !	 对所选行以外的所有行应用命令
 s	 用一个字符串替换另一个
 g	 在行内进行全局替换
 	
 w	 将所选的行写入文件
 x	 交换暂存缓冲区与模式空间的内容
 y	 将字符替换为另一字符(不能对正则表达式使用y命令)

3.2 sed选项

 -e	 进行多项编辑,即对输入行应用多条sed命令时使用
 -n	 取消默认的输出
 -f	 指定sed脚本的文件名

4. 正则表达式元字符

与grep一样,sed也支持特殊元字符,来进行模式查找、替换。不同的是,sed使用的正则表达式是括在斜杠线”/”之间的模式。 如果要把正则表达式分隔符”/”改为另一个字符,比如o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符即可。例如:sed -n ‘\o^Myop’ datafile

 元字符	|  功能和示例
-----------------------------
 ^	 	  |    行首定位符	 /^my/  匹配所有以my开头的行
 $	 	  |    行尾定位符	 /my$/  匹配所有以my结尾的行
 .	 	  |    匹配除换行符以外的单个字符	 /m..y/  匹配包含字母m,后跟两个任意字符,再跟字母y的行
 *	      |    匹配零个或多个前导字符	 /my*/  匹配包含字母m,后跟零个或多个y字母的行
 []	      |    匹配指定字符组内的任一字符	 /[Mm]y/  匹配包含My或my的行
 [^]	  |    匹配不在指定字符组内的任一字符	 /[^Mm]y/  匹配包含y,但y之前的那个字符不是M或m的行
 \(..\)	  |    保存已匹配的字符	 1,20s/\(you\)self/\1r/  标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。
		  |	   最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。
 &	      |    保存查找串以便在替换串中引用	 s/my/**&**/  符号&代表查找串。my将被替换为**my**
 \<	      |    词首定位符	 /\<my/  匹配包含以my开头的单词的行
 \>	      |    词尾定位符	 /my\>/  匹配包含以my结尾的单词的行
 x\{m\}	  |    连续m个x	 /9\{5\}/ 匹配包含连续5个9的行
 x\{m,\}  |	   至少m个x	 /9\{5,\}/  匹配包含至少连续5个9的行
 x\{m,n\} |    至少m个,但不超过n个x	 /9\{5,7\}/  匹配包含连续5到7个9的行

5. Favorite command

程序1:shell的某一行的某一列
#!/bin/bash
Fname=$1  
Lines=`cat $Fname |wc -l`  
for ((N=1;N<=$Lines;N++));  
do 
Var1=`sed -n "${N}p" $Fname`# 获得某一行  
Var2=`echo $Var1 |awk '{print $1}'`  
echo -e "当前处理的是第${N}行,\t内容是:$Var1,\t它的第一列值是$Var2"  
done; 

程序2:获得没有使用的磁盘
 # acquire a disk
ls /dev/sd* | awk '$1 !~/sda/' > tmp 
for nodisk in `df -lh | awk '$1 ~/sd/ {print $1;}'`; 
do 
awk '$1 !~/'${nodisk:5:3}'/' tmp > disks  #字符串第5个字符开始的3个字符
done 
TargetVolume=`sed -n "1p" disks`

程序3:打印多个,并查找字符串
awk '{print $3, $4}' hhb.txt > output.txt
sed -n '/hhb/'p > output.txt

程序4:如何修改文件
sed -i "s/BDF_TYPE=2/\BDF_TYPE=\"NIC\"/g" nic/m_ass/ts4_vf.sh

程序5:在某一行后面增

  1 #!/bin/sh
  2
  3 files= nic/pcie/ts2.sh nic/pci_nomsi/ts1_s3.sh nic/pci_nomsi/ts1.sh nic/pci_nomsi/ts2_s3.sh \
  4   nic/pci_nomsi/ts2.sh nic/m_ass_nomsi/ts1.sh nic/m_ass_nomsi/ts2.sh nic/m_ass/ts1.sh nic/m_ass/ts2.sh nic/hotplug/pci_32.sh \
  5   nic/hotplug/pci_64.sh nic/hotplug/pcie_32.sh nic/hotplug/pcie_64.sh nic/pcie_nomsi/ts1_s3.sh nic/pcie_nomsi/ts1.sh \
  6   nic/pcie_nomsi/ts2_s3.sh nic/pcie_nomsi/ts2.sh nic/hotplug_nomsi/pci_32.sh nic/hotplug_nomsi/pci_64.sh nic/hotplug_nomsi/pcie_32.sh \
  7   nic/hotplug_nomsi/pcie_64.sh nic/pci/ts1_s3.sh nic/pci/ts1.sh nic/pci/ts2_s3.sh nic/pci/ts2.sh
  8
  9 for file in  nic/pcie/ts2.sh nic/pci_nomsi/ts1_s3.sh nic/pci_nomsi/ts1.sh nic/pci_nomsi/ts2_s3.sh
 10 do
 11 sed -i "s/BDF_TYPE=1/BDF_TYPE=\"NIC\"/g" $file
 12 sed -i "/BDF_TYPE/a\BDF_SUB_TYPE=\"NIC\"" $file
 13 done

程序6:逐行读入文本-变量去除换行^M,\r,\n
cat keywords.txt |while read line
do
line=${line//[$'\t\r\n']}
cdomain=$line.$domain
done

程序7:SSH字符串处理
#!/bin/sh
set -x
. ./lib/VMMCommon.sh
hhb=`VMM_SSH ivt-ex2 "rdmsr 0x179" | grep password -A1 | sed -n 2p | awk '{print $1}'`
#hhd=${hhb//[$'\t\r\n']}
echo $((16#${hhb//[$'\t\r\n']})) $((16#8000000)) | awk '{print and($1, $2)}'

程序8: 替换某个变量的值
sed -i "s%^address.*$%address $virtual_ctrl_IP%g" $BASE_DIR/config/interfaces_ctrl
sed -i "s%^netmask.*$%netmask $virtual_ctrl_netmask%g" $BASE_DIR/config/interfaces_ctrl 
sed -i "s%^gateway.*$%gateway $virtual_ctrl_gateway%g" $BASE_DIR/config/interfaces_ctrl 

程序9 去除头部两个字符(一个字符一个点,头部 '^'),尾部('$')三个字符
echo 0x12343000 | sed 's/^.x//g' | sed 's/...$//g'

获取字符串第n个位置到m个位置
$ echo $gpa | cut -b3-7
 
$ export str="0x123000"
$ echo ${str:3:3}   // ${str:begin:len}
  230

按指定的字符串截取
${varible##*string} 从左向右截取最后一个string后的字符串
${varible#*string}从左向右截取第一个string后的字符串
${varible%%string*}从右向左截取最后一个string后的字符串
${varible%string*}从右向左截取第一个string后的字符串
“*”只是一个通配符可以不要
例子:
$ MYVAR=foodforthought.jpg
$ echo ${MYVAR##*fo}
rthought.jpg
$ echo ${MYVAR#*fo}
odforthought.jpg

截取字符变量的前8位,有方法如下:
1.expr substr “$a” 1 8
2.echo $a|awk ‘{print substr(,1,8)}’
3.echo $a|cut -c1-8
4.echo $
5.expr $a : ‘\(.\\).*’
6.echo $a|dd bs=1 count=8 2>/dev/null