sed笔记整理
介绍
sed是一款优秀的文本处理程序,但是其不同版本在用法和参数上存在着较大差异,建议大家在使用时一定要查询相关文档,以免出错。
以下示例大部分都是针对BSD版本的sed,因为OSX系统自带的sed就是这个版本,我是在mac上完成的相关测试。
一般linux的发布版带的都是GNU版本的,个人感觉,GNU版本的更强大和方便。
sed和perl正则表达式一些元字符的比较
+---------------------+
|perl |sed |
|-------+-------------|
|\d |[[:digit:]] |
|-------+-------------|
|\s |\s |
|-------+-------------|
|+ |\+ |
|-------+-------------|
|{num} |\{num\} |
+---------------------+
常用命令
如果希望直接在源文件中修改,传参数-i[.bak]
,在GNU sed中,.bak
可选,但是在BSD sed中,必须添加,可以传递空字符串来表示直接修改源文件,即使用-i ''
用于测试的pets.txt下载
# 删除只有空白字符行
sed -i -e '/^\s\+$/d' file #GNU
sed '1!G;h;$!d' pets.txt #反转一个文件的行
sed 'N; s/\n /, /' pets.txt #将两行合并,并用逗号分开
sed -e 's/'$(echo -e "\x15")'//g' file # sed用于去除ascii不可打印的控制字符
# 常规的替换功能
sed "s/my/Hao Chen's/" pets.txt
sed "3s/my/your/" pets.txt
sed "3,6s/my/your/" pets.txt #只替换第3到第6行的文本
sed -n '/cat/,/fish/p' pets.txt # 只打印匹配cat和fish之前的行,-n表示不输出那些未匹配的行
sed -e 3,6{ -e /This/d -e } pets.txt
sed '3,6{/This/d;}' pets.txt #BSD sed, must add semi-colon
sed '3,6 {/This/{/fish/d;};}' pets.txt
sed '1,${/This/d;s/^ *//g;}' pets.txt
sed -E '/dog/{N;N;N;s/(^|\n)/&# /g;}' pets.txt #BSD sed
sed '/dog/,+3s/^/# /g' pets.txt #GNU sed
sed = pets.txt | sed 'N;s/\n/'$'\t''/' > line_num_pets.txt
sed = my.txt | sed 'N; s/^/ /; s/\(.\{5,\}\)\n/\1 /' #对文件中的所有行编号(行号在左,文字左端对齐)。
#sed = my.txt | sed -E 'N; s/(.*)\n/ \1 /' #貌似,我也可以这么写
sed '/'"$name"'/,/};/d' back_slash.txt
#实际应用,用来做代码重构时:(err) -> next err => next
find . -name '*.coffee' | xargs sed -i '' -E '/\(err\) ->/{N;s/\(err\) ->\n +next err/next/g;}'
#在多行的时候,[[:space:]]才会匹配换行符\n,只有单行的时候,字符串尾部的换行符已经被sed截掉,所以匹配不到
#使用GNU sed去掉首行的BOM
find . -name '*.srt' -exec gsed -i -e '1s/^\xEF\xBB\xBF//' {} \;
gsed '1~2G' -i *.txt #奇数行后加空行
gsed -i -e '$a\' file #如果文件末尾没有换行符,则自动添加,解决"No newline at end of file"的问题,OSX sed中:sed -i '' -e '$a\'
除了在命令行中使用字符串输入,也可以使用处理脚本作为输入,脚本3_6下载
sed -f 3_6 pets.txt #use file
神奇用法
# BSD sed中,插入一段文本的做法
sed -iold '1i\'$'\n''text to prepend'$'\n' file.txt
# $'\n'是bash中的换行符,具体执行原理如下:
sed -iold '1i\'$'\n''text to prepend'$'\n' file.txt
^^^^^^^^ ^
/ |\|||/ \ |__ No need to reopen
| | \|/ | string to sed
Tells sed to | | | |
escape the next _/ | | +-----------------------------+
char | +-------------+ |
| | |
Close string The special bash Reopen string to
to sed newline char to send to sed
send to sed
下面为应用以上原理的示例。这些示例都是针对BSD sed的。当替换文本中有单引号时,可以使用双引号圈引,减少转义。这是用于测试的my.txt下载
# 在第1行插入内容
sed "1i\\"$'\n'"my monkey's name is wukong"$'\n' my.txt
# 在最后一行追加内容
sed "$ a \\"$'\n'"my monkey's name is wukong"$'\n' my.txt
# 在匹配行之前插入内容
sed "/fish/i\\"$'\n'"my monkey's name is wukong"$'\n' my.txt
# 在指定行修改为特定内容
sed "2c \\"$'\n'"my monkey's name is wukong"$'\n' my.txt
# 将my.txt中,每行的s,从第2个开始,全部替换为xxx
sed 's/s/\'$'\n''xxx/2;h;s/s/xxx/g;H;g;s/\n.*\n//' my.txt
单行命令总结
# 匹配行后追加内容
gsed -i '/matchpattern/a content' tmp.txt
# 如果content是以空白字符开头,比如tab或者空格,则用一个反斜线标记出来
gsed -i '/matchpattern/a \ content' tmp.txt
# 命令行中输入tab键:先按ctrl+v,然后再按tab
gsed -i '/matchpattern/a \ content' tmp.txt
# 匹配行后追加多行内容,可以把需要追加的内容写到一个文件中,然后使用r命令
gsed -i '/abcd/r otherfile.txt' tmp.txt
# 删除匹配行之前的内容,也就是保留匹配行之后的所有内容
sed -i '/^package /,$!d' *.go
# 显示一定范围内的行
sed -n '190,200p' tmp.txt