一直没有系统学习过
sed
,这里是一些例子的汇总整理,快刀斩乱麻......
样例文本file
内容如下
Cygwin
Unix
Linux
Solaris
AIX
- 删除文件中指定行
例如删除第1行
sed '1d' file
删除第3行
sed '3d' file
上述
sed
命令是直接将sed
修改后的内容出处到标准输出(屏幕)上,而源文件不变。要更新源文件,需要加上-i
参数。例如:
sed -i '3d' file
sed
是将源文件复制后修改,所以-i
参数实际是修改后覆盖源文件
在 sed
中, $
代表最后一行,所以删除最后一行可以使用如下命令:
sed '$d' file
此外, head
命令提供了一个更好的删除最后几行的方法, -n -X
:通常 -n X
表示打印前X行,当 X
前面加上 -
则表示倒过来,即打印所有行但不包括最后的X行,也就是输出内容少了最后 X
行,所以定向到新文件就能截断原文件的最后 X
行(以下案例去除了file.txt文件的最后3行生成new_file.txt):
cat file.txt | head -n -3 > new_file.txt
删除第2行到第四行
sed '2,4d' file
保留第2行到第4行,删除其余行(反转选择就是加上!
符号)
sed '2,4!d' file
这里输出就是
Unix
Linux
Solaris
删除第1行和最后一行(注意:每一行之间用;
分隔)
sed '1d;$d' file
同上,如果要删除第2行和第4行,就使用
'2d;3d'
- 匹配并删除
删除带有一个特定字符开头的行,例如,L
开头的行
sed '/^L/d' file
这里输出就是
Cygwin
Unix
Solaris
AIX
删除x
结尾的行
sed '/x$/d' file
还支持正则,例如,要删除x
或X
结尾的行
sed '/[xX]$/d' file
删除文件中的空白行
sed '/^$/d' file
^
表示开头,$
表示结尾,由于中间没有任何字符,就是空白行
删除空白行或者包含一些空格的行
sed '/^ *$/d' file
这里
*
表示0个或者多个重复的前一个字符,这里前一个字符是空格,所以这里*
就表示有一个空格或者多个空格。此时会删除完全空白行,以及包含一个或多个空格的空白行。
删除全部是大写字符的行(这里会删除AIX
行)
sed '/^[A-Z]*$/d' file
[A-Z]
表示全部大写字母,后面跟了*
表示前面的[A-Z]
字符重复(任意大写字符),也就是表示整行都是大写字符,所以就删除了AIX
删除没有包含字符串Unix
的行
sed '/Unix/!d' file
删除包含Unix
或Linux
的行(或的符号是|
,注意需要加转义符)
sed '/Unix\|Linux/d' file
删除从第一行到匹配上Linux
的行
sed '1,/Linux/d' file
输出的结果是
Solaris
AIX
删除从匹配Linux
行到文档最后行
sed '/Linux/,$d' file
如果最后一行包含了AIX
,则删除最后一行(如果最后一行是其他内容则不删除)
sed '${/AIX/d;}' file
输出内容是
Cygwin
Unix
Linux
Solaris
这里
$
表示最后一行,只在这行包含了AIX
才删除,这里引入了if
判断(也就是{}
表示if
条件)
如果最后一行包含了AIX
或者HPUX
则删除最后一行
sed '${/AIX\|HPUX/d;} file
只在第1行到第4行之间出现Solaris
字符串匹配情况下删除这行:
sed '1,4{/Solaris/d;}' file
如果一行中包含了Unix
关键字,则删除这行和下面一行
sed '/Unix/{N;d;}' file
这里
N
命令读取匹配行的下一行,而d
命令则删除匹配行和下一行
上述命令输出是
Cygwin
Solaris
AIX
只删除包含了Unix
的下一行(但Unix
行不删除)
sed '/Unix/{N;s/\n.*//;}' file
输出内容是
Cygwin
Unix
Solaris
AIX
sed - 25 examples to delete a line or pattern in a file原文还有3个例子较为复杂:
删除匹配行和匹配行之前的行
sed -n '/Linux/{s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d'
删除包含Linux
的行之前的行,但不删除'Linux'行:
sed -n '/Linux/{x;d;};1h;1!{x;p;};${x;p;}' file
删除包含Linux
行以及之前的行和之后好的行
sed -n '/Linux/{N;s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d'
- 合并重复的空格成一个空格
在使用cut
工具来截取ps
出来的进程的pid
,会遇到一个问题,就是每列之间的空格数量是不一定的,这样虽然可以通过awk
来截取,但是蹪于cut
命令就不行了。解决的方法是将多个空格合并成一个空格,sed
命令提供了这个功能:
ps axu | grep '[j]boss' | sed 's/\s\+/ /g' | cut -d' ' -f2
这里使用的是GNU sed,这个sed提供了
\s
表示空格(扩展),\+
表示多个空格
或者
ps axu | grep '[j]boss' | sed 's/\s\s*/ /g' | cut -d' ' -f2
不过,在OS X中,需要传递
-E
参数来激活sed扩展正则表达式,然后使用[[:space:]]
来代替\s
,也就是
ps axu | grep '[j]boss' | sed -E 's/[[:space:]]+/ /g' | cut -d' ' -f2
请参考cut使用举例
- 替换换行符(
\n
): 读取整个文件替换换行符成一个空格
sed ':a;N;$!ba;s/\n/ /g'
首先创建一个label
:a
通过
N
将当前行和下一行通过空格连接如果到了最后一行,则创建label
$!ba
(这里$!
表示不在最后一行做这个操作)最后使用在模式坑拜拜中的空格来替换每个换行符
上述方法实在太拗口,其实可以使用tr
工具来实现这个任务
tr '\n' ' ' < input_filename
或者
tr --delete '\n' < input.txt > output.txt
- 在匹配行的最后添加内容
sed -i '/kernel \/boot/s/$/ clocksource_failover=acpi_pm/' /boot/grub/grub.cfg
sed -i '/vmlinuz-2.6.32/ s/$/ intremap=off/' /boot/grub/grub.conf
上述方法简单来说就是先匹配,然后搜索到最后的标志
$
,再进行替换。
参考
How to append a string at end of a specific line in a file in bash
Add to the end of a line containing a pattern - with sed or awk
- 将换行符
\n
替换成字符
例如,我有一个文件包含了多个主机名(每行是一个主机名),但是提交到某个平台的时候,格式要求使用,
分隔,则可以通过sed来替换换行符\n
sed ':a;N;$!ba;s/\n/,/g' file
含义如下:
- 创建一个标签(liabel)
:a
- 通过添加
N
到当前和下一行的位置 - 如果在最后一行之前,则创建标签
$!ba
($!
表示如果最后一行就不做) - 最后将所有换行符替换成
,
上述命令是使用GNU sed,如果是跨平台,则使用BSD sed
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/,/g'
参考 How can I replace a newline (\n) using sed?
更为简单的方法是使用
tr
,不过结尾多一个,
tr '\n' ',' < input_filename
怎样去除最后一个字符,应该可以使用sed
或awk
,不过 Delete the last character of a string using string manipulation in shell script 提供了一个巧妙的方法,组合利用rev
命令和cut
命令。即先将字符串倒转(rev
),然后用cut -c 2-
截取出(n+1)-
之后所有字符,然后再倒转回来
cat input_filename | tr '\n' ',' | rev | cut -c 2- | rev
还有一种方法是使用bash 4.2之后,支持字符串变量切片
a=`cat input_filename | tr '\n' ','`
echo "${a::-1}"
例如我需要修改 /etc/fstab
,将包含 swap
行注释掉。参考 sed - Commenting a line matching a specific string AND that is not already commented out
原先的 /etc/fstab
内容如下:
...
UUID=57e88efb-83f7-42a3-8080-f943626bd7f7 swap swap defaults 0 0
修改命令如下:
sed -i -e '/swap/s/^UUID=/#UUID=/g' /etc/fstab
上述表示先匹配swap行,然后搜索 UUID=
开头的内容替换成 #UUID=
当需要向海量服务器部署配置脚本,但是配置脚本中某些字符串和服务器主机名相关(需要改成主机名),则可以模仿puppet
之类的配置管理工具,采用配置文件中占位符方式来实现。
即预先分发的配置文件中包含一些特定的预先占好位置的变量字符串(具有特征,如全大写,或者有特殊符号),在分发完成后,采用pssh命令对配置文件中占位符变量进行替换。
举例:配置文件 /etc/example.conf
内容如下:
...
console name='HOSTNAME' dev='/dev/null' opts='-o example'
HOSTNAME
就是需要替换的占位符变量
通过pscp
分发完配置文件到所有服务器之后,就可以通过以下pssh
命令将每个主机的主机名提取出来,然后用实际主机名替换HOSTNAME
:
pssh -ih server_list "HOST=\$(hostname);sudo sed -i \"s/HOSTNAME/\$HOST/\" /etc/example.conf"
sed支持一次检查多个匹配,实际上就是sed多个指令的意思。注意:指令之间使用;
分隔:
sed -i '/PATTERN_1/d;PATTERN_2/d;PATTERN_3/d;/^$/d' myfile.txt
- unix2dos
sed 's/$'"/`echo \\\r`/" disk.txt > disk_dos.txt
- dos2unix
sed 's/^M$//' disk_dos.txt > disk.txt
参考 HowTo: UNIX / Linux Convert DOS Newlines CR-LF to Unix/Linux Format