sed 入门详解

本贴最后更新于 2020 天前,其中的信息可能已经渤澥桑田

由于 sed 命令本身特别复杂,完全把此命令搞明白并记住不忘是非常困难的.因此能够对于一些经常使用的场景总结出最佳实践一个不错的方式.

sed 工作模式

其命令格式如下:

sed -e [option] 'command' file

command 的格式构成

[addr]X[options]

一个命令由地址空间,命令字母,以及相应的命令选项(可选),比如命令:4,5p;q43;首先匹配地址空间 4 行与 5 行,然后执行打印命令 p,命令 p 没有带可选参数,打印完成后执行 q 命令,命令 q 带了可选项参数:42 表明命令的退出 code 为:42;下面对此命令格式进行详细的介绍;

[addr]

一个地址空间是后面跟的命令的执行匹配行的一个选择条件.后面的命令只对此地址空间匹配的行产生作用;如下命令:

sed '144s/hello/world/' input.txt > output.txt

Addresses determine on which line(s) the sed command will be executed. The following command replaces the word ‘hello’ with ‘world’ only on line 144:

如果没写地址空间选项,后面的命令将会在所有的行上进行操作,下面的命令将替换所有行中的单词:helloworld(注:只会替换一行中出现的第一个 hello 单词):

sed 's/hello/world/' input.txt > output.txt

除了使用行号,地址空间也可以包含一个正则表达式来匹配满足此表达式的行;下面的命令将会替换包含单词:apple 的行的 helloworld:

sed '/apple/s/hello/world/' input.txt > output.txt

一个地址范围通过两个地址指定,地址之间用 , 分隔;地址可以是数字,正则表达式,或者是两者的混合;下面的命令仅仅在 4 到 17 行,替换单词 helloworld;

sed '4,17s/hello/world/' input.txt > output.txt

可以添加符号:! 来取地址空间的补集:取反(在命令字母前面添加);下面的命令替换单词 helloworld 仅仅在那些不包含单词:apple 的行中:

sed '/apple/!s/hello/world/' input.txt > output.txt

The following command replaces the word ‘hello’ with ‘world’ only in lines 1 to 3 and 18 till the last line of the input file (i.e. excluding lines 4 to 17):

sed '4,17!s/hello/world/' input.txt > output.txt

X

X 是一个单字母命令

其常用的命令有:

命令 说明 示例
# 注释 '4,5p # 打印输出4到5行'
p 打印匹配行 '4,5p'
s 对匹配行进行替换操作 s/a/b/g
= 显示文件行号 sed -ne '=;p' aaa.txt
d 删除定位行:Delete the pattern space; immediately start next cycle. sed -e '4,5d' aaa.txt
q 第一个模式匹配完成后退出或立即退出
n If auto-print is not disabled, print the pattern space, then, regardless, replace the pattern space with the next line of input. If there is no more input then sed exits without processing any more commands. This command is useful to skip lines (e.g. process every Nth line).
{cmds} 一个命令组可以用{}包起来,这个会特别有用.当你想一组命令被一个单地址,或者是地址范围触发时
[options]

options 选项针对不同的具体命令有具体的使用方法,也有可能不带选项;

一个脚本命令行或者是一个脚本文件里的命令可以使用分号进行分隔(;),或者是使用新行进行分隔('\n',ascii 码值为 10);多个脚本可以被同时用参数 -e 或者是 -f 指定;

注:

如上面的命令组 {} 的意义与区别在于,每一个命令是以[地址]X[选项]进行书写,因此这就是一个完整的命令.下一个命令与上一个命令之间由上面的知识可知是通过分号 ; 或者是新行 \n 进行分隔;因此多个命令看起来是这样的 3,5p;6,7a//this is a comment; 这里有两个命令,如果这两个命令的地址范围都是 3,5,那可以合并为一个命令组:

seq 10 | sed -n -e '3,5{a//this is a comment;
p;
}'

打印命令 p

打印单行

echo "$var" | sed -n -e '5p' #打印第五行
echo "$var" | sed -n -e '5p;5q;' #打印第五行高效模式
echo "$var" | sed -n -e '$p' #打印最后一行

打印多行

echo "$var" | sed -n -e '5,8p' #打印第5到8行
echo "$var" | sed -n -e '5,$p' #打印第5到最后一行

替换命令: s

s 命令(即替换命令)可能是 sed 最重要的命令,它包含非常多的选项,此命令的语法为:'s/regexp/replacement/flags'
其基本概念特别简单:s 命令尝试使用命令中的 正则表达式 去匹配 模式空间 中的字符串;如果匹配成功,模式空间中的匹配项将会被 replacement 替代

标准命令如下, origin 是一个正则表达多,replacement 是替换后的目标字符串

# 标准命令
sed -e 's/regexp/replacement/flags' filename.txt
# 简化命令
sed 's/origin/replacement/' filename.txt

aaa 替换成 bbb (第一匹配组)

echo "aaa ccc bbb ddd eee" | sed -e 's/aaa/bbb/'

aaa 替换成 bbb (指定匹配组)

# 替换第二个 'aaa' 为 'bbb'
echo "aaa aaa bbb ddd eee" | sed -e 's/aaa/bbb/2'

aaa 替换成 bbb (全部替换)

# 替换所有 aaa 为 bbb
echo "aaa aaa bbb ddd eee" | sed -e 's/aaa/bbb/g'

s 命令中的分隔符号 /

The / characters may be uniformly replaced by any other single character within any given s command. The / character (or whatever other character is used in its stead) can appear in the regexpor replacement only if it is preceded by a \ character.

在替换命令中(即 s 命令)的 / 是可以用任意字符来分隔的:

# 最常见的形式
echo "aaa bb cc" | sed -e 's/a/b/g'
# 这里用#分隔
echo "aaa bb cc" | sed -e 's#a#b#g'
# 用 空格分隔
echo "aaa bb cc" | sed -e 's a b g'

目标串中的 &

在字符串替换的时候,& 代表匹配的字符串的值
场景: 给电话号码添加双引号

echo "phoneNumber:13800138000" | sed  -E 's/[0-9]{11}/"&"/g'
phoneNumber:"13800138000"

目标串中使用匹配组

The replacement can contain \n(n being a number from 1 to 9, inclusive) references, which refer to the portion of the match which is contained between the nth \( and its matching \). Also, the replacement can contain unescaped & characters which reference the whole matched portion of the pattern space.

场景: phone:13800138000 修改为:{"phone": "13800138000"}

# 修改需要的部分
echo "something*&&&^^^phone:13800138000sfjdskfsfe" | sed -E 's/(phone):([0-9]{11})/{"\1":"\2"}/g'
# 只输出需要的部分
echo "something*&&&^^^phone:13800138000sfjdskfsfe" | sed -E 's/.*(phone):([0-9]{11}).*/{"\1":"\2"}/g'

去除文件中的 '\r'

echo -e "aaa\r\nbbb\r\nccc" > aaa.txt
sed -e $'s/\r//g' aaa.txt | od -c

行合并

This section uses N,D and P commands to process multiple lines, and the b and t commands for branching

合并特定行

$ cat lines.txt
hello
hel
lo
hello

$ sed '2{N;s/\n//;}' lines.txt
hello
hello
hello

命令解释:

2{N;s/\n//;} 匹配上第二行后,执行命令块:{N;s/\n//;},命令块先再读取下一行(命令 N),执行 s 命令;搜索 \n 替换为空 ,这样 2-3 行合并在一行.其它行没有匹配上.直接原样输出;

合并 '\' 换行的多行

$ cat 1.txt
this \
is \
a \
long \
line
and another \
line

$ sed -e ':x /\\$/ { N; s/\\\n//g ; bx }'  1.txt
this is a long line
and another line

#TODO: The above requires gnu sed.
#      non-gnu seds need newlines after ':' and 'b'

命令解释:

:x /\\$/ { N; s/\\\n//g ; bx }

  1. 首先定义一个标号 x;
  2. 匹配以 \ 结尾的行,由于 \ 是特殊字符.因此需要转义 \\,同时只匹配以 \ 结尾的行,因此 \ 后面加了一个 $;
  3. 搜索到行后,执行命令块:{ N; s/\\\n//g ; bx };
  4. 以上命令块是一个循环,首先读取下一行.同上,替换 \n 为空;然后无条件跳转 b 到标签 x;
    5.此时再匹配当前行是否以 \ 结尾;注意此时行已经发生变化,读取了下一行;

文本多行转一行,并且以 , 分隔

### 无法实现
echo -e "aaa\nbbb\nccc" > aaa.txt
sed -e 's/\n/,/g' aaa.txt

以上代码无法执行的原因是可以参考:sed 列转行无法返回是因为其处理机制的问题

说明:sed 默认只按行处理,N 可以让其读入下一行,再对\n 进行替换,这样就可以将两行并做一行。但是怎么将所有行并作一行呢?可以采用 sed 的跳转功能。:a 在代码开始处设置一个标记 a,在代码执行到结尾处时利用跳转命令 t a 重新跳转到标号 a 处,重新执行代码,这样就可以递归的将所有行合并成一行。

sed ':a ; $!N; s/\n/,/ ; t a ; '  aaa.txt

命令解释:

命令片断 说明 作用
:a 定义一个标签 用于控制后面的循环
$!N $ 表示最后一行,$! 表示非最后一行,N 表示向 模式空间中追加下一行 非尾行时追加一行数据到 模式空间
s/\n/,/ ; 执行 s 替换命令,把拼接的两行中 \n 替换为 , 完成两行合并,去除换行
t a ; 如果最后一次输入的最后一个 s/// 子命令执行成功,跳转到标签 a,否则跳转到结束 控制循环,直到读取到最后一行

b label ,无条件跳转到标签 label,如果 label 没有指定,跳转到命令的结尾
t label ,如果最后一次输入的最后一个 s/// 子命令执行成功,跳转到标签 label,如果 label 没有指定,跳转到命令的结尾

  1. sed 命令换行符问题以及跳转命令-对文件处理,整个文件先转换为一行处理完后再把换行加上
  2. sed 中跳转命令的用法
  3. 文本编辑的一点心得--sed 篇
  4. 抛砖引玉----翻译加注 sed1line
  5. Linux 命令之 grep/sed/awk 等行转列
  6. Linux 命令大全-sed
  7. sed 循环
  8. sed 命令替换换行符(同 1)
  9. sed 命令详解
  10. sed 常用命令
  11. Sed 命令的使用详细解释
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    123 引用 • 74 回帖
  • Bash
    10 引用 • 21 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...