一直没有系统学习过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 '$d' file

删除第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

还支持正则,例如,要删除xX结尾的行

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

删除包含UnixLinux的行(或的符号是|,注意需要加转义符)

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

怎样去除最后一个字符,应该可以使用sedawk,不过 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}"

参考

results matching ""

    No results matching ""