高级sed编辑器使用指南
1. 保留空间(Holding Space)
在sed编辑器处理命令时,模式空间(pattern space)是一个活跃的缓冲区,用于存储正在检查的文本。不过,sed编辑器还有另一个缓冲区,即保留空间(hold space)。保留空间可用于临时保存文本行,以便在处理模式空间中的其他行时使用。与保留空间操作相关的五个命令如下表所示:
| 命令 | 描述 |
|---|---|
| h | 将模式空间复制到保留空间 |
| H | 将模式空间追加到保留空间 |
| g | 将保留空间复制到模式空间 |
| G | 将保留空间追加到模式空间 |
| x | 交换模式空间和保留空间的内容 |
下面是一个简单的示例,展示了如何使用
h
和
g
命令在sed编辑器的缓冲区之间来回移动数据:
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed -n '/First/ {
> h ; p ;
> n ; p ;
> g ; p }
> ' data2.txt
First Data Line
Second Data Line
First Data Line
$
具体步骤如下:
1. sed脚本使用正则表达式过滤包含单词
First
的行。
2. 当包含
First
的行出现时,
h
命令将模式空间中的行复制到保留空间,此时模式空间和保留空间的数据相同。
3.
p
命令打印模式空间的内容(即
First Data Line
)。
4.
n
命令获取数据流中的下一行(
Second Data Line
)并放入模式空间,此时模式空间和保留空间的数据不同。
5.
p
命令打印模式空间的内容(
Second Data Line
)。
6.
g
命令将保留空间的内容(
First Data Line
)放回模式空间,替换当前文本,此时模式空间和保留空间的数据再次相同。
7.
p
命令打印模式空间的当前内容(
First Data Line
)。
如果去掉第一个
p
命令,就可以按相反顺序输出这两行:
$ sed -n '/First/ {
> h ;
> n ; p
> g ; p }
> ' data2.txt
Second Data Line
First Data Line
$
2. 否定命令(Negating a Command)
感叹号(
!
)命令用于否定一个命令。也就是说,在正常情况下会激活的命令,使用
!
后将不会被激活。例如:
$ sed -n '/Header/!p' data2.txt
First Data Line
Second Data Line
End of Data Lines
$
正常的
p
命令只会打印
data2
文件中包含单词
Header
的行。添加感叹号后,情况相反,文件中除了包含
Header
的行之外的所有行都会被打印。
感叹号在一些应用中非常有用。例如,在处理数据流的最后一行时,某些sed命令可能无法正常工作,因为没有后续行。可以使用感叹号来解决这个问题:
$ cat data4.txt
On Tuesday, the Linux System
Admin group meeting will be held.
All System Admins should attend.
$
$ sed 'N;
> s/System\nAdmin/DevOps\nEngineer/
> s/System Admin/DevOps Engineer/
> ' data4.txt
On Tuesday, the Linux DevOps
Engineer group meeting will be held.
All System Admins should attend.
$
$ sed '$!N;
> s/System\nAdmin/DevOps\nEngineer/
> s/System Admin/DevOps Engineer/
> ' data4.txt
On Tuesday, the Linux DevOps
Engineer group meeting will be held.
All DevOps Engineers should attend.
$
在这个例子中,感叹号与
N
命令和美元符号(
$
)特殊地址一起使用。美元符号表示数据流中的最后一行,所以当sed编辑器到达最后一行时,不会执行
N
命令,但对于其他行,会执行该命令。
利用这个技术,可以反转数据流中文本行的顺序。具体步骤如下:
1. 将文本行放入模式空间。
2. 将模式空间中的行复制到保留空间。
3. 将下一行文本放入模式空间。
4. 将保留空间追加到模式空间。
5. 将模式空间中的所有内容复制到保留空间。
6. 重复步骤3到5,直到将所有行以相反顺序放入保留空间。
7. 检索并打印这些行。
graph TD;
A[文本行放入模式空间] --> B[复制到保留空间];
B --> C[放入下一行到模式空间];
C --> D[追加保留空间到模式空间];
D --> E[复制模式空间到保留空间];
E --> C;
E --> F{是否处理完所有行};
F -- 是 --> G[打印结果];
F -- 否 --> C;
为了实现这个功能,需要使用以下命令:
-
1!G
:避免将保留空间追加到第一行。
-
h
:将新的模式空间复制到保留空间。
-
$p
:当到达数据流的最后一行时,打印结果。
测试示例如下:
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed -n '{1!G ; h ; $p }' data2.txt
End of Data Lines
Second Data Line
First Data Line
Header Line
$
3. 改变流程(Changing the Flow)
3.1 分支(Branching)
sed编辑器提供了一种基于地址、地址模式或地址范围来否定整个命令部分的方法,从而只对数据流中的特定子集执行一组命令。分支(
b
)命令的格式如下:
[address]b [label]
-
address参数确定触发分支命令的数据行。 -
label参数定义脚本中要分支到的位置。如果没有label参数,分支命令将跳过触发分支的数据行,继续处理其他文本行。
下面是一个使用地址参数但没有标签的分支命令示例:
$ cat data2.txt
Header Line
First Data Line
Second Data Line
End of Data Lines
$
$ sed '{2,3b ;
> s/Line/Replacement/}
> ' data2.txt
Header Replacement
First Data Line
Second Data Line
End of Data Replacements
$
分支命令跳过了数据流中第二行和第三行的替换命令。
也可以定义一个标签,让分支命令跳转到该位置。标签以冒号开头,长度最多为七个字符。例如:
$ sed '{/First/b jump1 ;
> s/Line/Replacement/
> :jump1
> s/Line/Jump Replacement/}
> ' data2.txt
Header Replacement
First Data Jump Replacement
Second Data Replacement
End of Data Replacements
$
如果行中出现匹配文本
First
,分支命令将跳转到标有
jump1
的脚本行。如果分支命令的地址不匹配,sed编辑器将继续处理脚本中的命令。
还可以分支到脚本中较早出现的标签,从而创建循环效果:
$ echo "This, is, a, test, to, remove, commas." |
> sed -n '{
> :start
> s/,//1p
> b start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
^C
$
为了防止出现无限循环,可以为分支命令指定一个地址模式。例如:
$ echo "This, is, a, test, to, remove, commas." |
> sed -n '{
> :start
> s/,//1p
> /,/b start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
$
3.2 测试(Testing)
测试(
t
)命令也用于修改sed编辑器脚本的流程。与分支命令不同,
t
命令根据前面替换命令的结果跳转到标签。如果替换命令成功匹配并替换了模式,测试命令将分支到指定的标签;如果替换命令未匹配指定模式,测试命令将不分支。
测试命令的格式与分支命令相同:
[address]t [label]
如果不指定标签,当测试成功时,sed将跳转到脚本命令的末尾。
下面是一个使用测试命令的示例:
$ sed '{s/First/Matched/ ; t
> s/Line/Replacement/}
> ' data2.txt
Header Replacement
Matched Data Line
Second Data Replacement
End of Data Replacements
$
第一个替换命令查找模式文本
First
。如果匹配成功,替换文本,测试命令将跳过第二个替换命令;如果未匹配,将处理第二个替换命令。
使用测试命令可以改进之前使用分支命令的循环:
$ echo "This, is, a, test, to, remove, commas." |
> sed -n '{
> :start
> s/,//1p
> t start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
$
当没有更多逗号需要替换时,测试命令将不再分支,处理结束。
4. 通过模式替换(Replacing via a Pattern)
4.1 使用通配符替换的问题
在sed命令中使用模式替换数据流中的文本时,如果使用通配符,可能会遇到一些问题。例如:
$ echo "The cat sleeps in his hat." |
> sed 's/.at/".at"/g'
The ".at" sleeps in his ".at".
$
替换字符串使用了点通配符来匹配任何以“at”结尾的字母,但替换字符串没有匹配到匹配单词的通配符值。
4.2 使用&符号
sed编辑器提供了一个解决方案,即使用&符号来表示替换命令中匹配的模式。无论什么文本匹配了定义的模式,都可以在替换模式中使用&符号来引用它。例如:
$ echo "The cat sleeps in his hat." |
> sed 's/.at/"&"/g'
The "cat" sleeps in his "hat".
$
4.3 替换单个单词
&符号会检索替换命令中指定模式匹配的整个字符串。有时,你可能只想检索字符串的一个子集。sed编辑器使用括号来定义替换模式中的子字符串组件,然后可以在替换模式中使用特殊字符来引用每个子字符串组件。替换字符由反斜杠和数字组成,数字表示子字符串组件的位置。例如:
$ echo "The Guide to Programming" |
> sed '
> s/\(Guide to\) Programming/\1 DevOps/'
The Guide to DevOps
$
这个替换命令使用括号将
Guide to
标识为子字符串组件,然后在替换模式中使用
\1
来引用它。
再看一个例子:
$ echo "That furry cat is pretty." |
> sed 's/furry \(.at\)/\1/'
That cat is pretty.
$
$ echo "That furry hat is pretty." |
> sed 's/furry \(.at\)/\1/'
That hat is pretty.
$
在这种情况下,不能使用&符号,因为它会替换整个匹配的模式。子字符串组件提供了解决方案,允许你选择模式的哪一部分作为替换模式。
高级sed编辑器使用指南
5. 其他实用技巧总结
在使用sed编辑器时,除了前面介绍的保留空间、否定命令、改变流程和模式替换等技巧外,还有一些其他实用的要点需要注意。
5.1 命令组合的灵活性
sed允许将多个命令组合在一起使用,以实现更复杂的文本处理。例如,结合分支和替换命令,可以根据不同的条件对文本进行不同的处理。以下是一个示例:
$ cat data3.txt
Apple
Banana
Cherry
Date
$
$ sed '{/Banana/b special ; s/[a-zA-Z]*/& Fruit/ ; :special ; s/[a-zA-Z]*/& Special Fruit/ }' data3.txt
Apple Fruit
Banana Special Fruit
Cherry Fruit
Date Fruit
$
在这个例子中,如果文本行包含
Banana
,则跳转到
special
标签处进行特殊处理,否则进行普通的替换操作。
5.2 利用注释提高脚本可读性
在编写复杂的sed脚本时,可以使用注释来提高脚本的可读性。虽然sed本身没有专门的注释语法,但可以通过在脚本中添加不影响命令执行的字符来模拟注释。例如:
$ sed '{
# 查找包含Apple的行
/Apple/ {
# 将其替换为Apple Delicious
s/Apple/Apple Delicious/
}
# 对其他行进行普通替换
s/[a-zA-Z]*/& Generic/
}' data3.txt
这里使用
#
开头的行作为注释,帮助理解脚本的逻辑。
6. 实际应用场景分析
了解了sed的各种高级技巧后,我们来看一些实际的应用场景。
6.1 日志文件处理
在处理日志文件时,可能需要过滤掉一些无用的信息,提取关键数据。例如,有一个日志文件
log.txt
,内容如下:
[2024-01-01 10:00:00] INFO: User logged in: John
[2024-01-01 10:01:00] DEBUG: Some debug message
[2024-01-01 10:02:00] INFO: User logged out: John
如果我们只关心用户登录和退出的信息,可以使用sed进行过滤:
$ sed -n '/INFO: User/p' log.txt
[2024-01-01 10:00:00] INFO: User logged in: John
[2024-01-01 10:02:00] INFO: User logged out: John
$
还可以进一步提取用户名:
$ sed -n '/INFO: User/ s/.*: //p' log.txt
John
John
$
6.2 配置文件修改
在修改配置文件时,sed可以快速定位并修改特定的配置项。例如,有一个配置文件
config.ini
,内容如下:
[database]
host = localhost
port = 3306
username = root
password = secret
如果要将数据库主机修改为
new_host
,可以使用以下命令:
$ sed 's/host = .*/host = new_host/' config.ini
[database]
host = new_host
port = 3306
username = root
password = secret
$
7. 性能优化建议
在处理大量数据时,sed的性能可能会成为一个问题。以下是一些性能优化的建议:
7.1 减少不必要的命令
尽量避免在脚本中使用过多的命令,尤其是一些复杂的正则表达式和循环。例如,如果只需要简单的替换操作,就不要使用复杂的分支和测试命令。
7.2 批量处理
如果需要处理多个文件,可以将多个文件一起传递给sed,而不是一个一个地处理。例如:
$ sed -i 's/old_text/new_text/' file1.txt file2.txt file3.txt
这里的
-i
选项表示直接在文件中进行替换。
7.3 合理使用正则表达式
正则表达式的复杂度会影响sed的性能。尽量使用简单的正则表达式,避免使用过于复杂的模式匹配。
总结
sed编辑器是一个强大的文本处理工具,通过掌握其高级技巧,如保留空间的使用、否定命令、改变流程、模式替换等,可以实现复杂的文本处理任务。在实际应用中,要根据具体的需求选择合适的技巧,并注意性能优化。通过不断的实践和总结,你将能够熟练运用sed编辑器,提高工作效率。
| 技巧 | 描述 | 示例 |
|---|---|---|
| 保留空间 | 用于临时保存文本行,通过特定命令在模式空间和保留空间之间移动数据 |
sed -n '/First/ { h ; p ; n ; p ; g ; p }' data2.txt
|
| 否定命令 |
使用
!
否定命令的执行
|
sed -n '/Header/!p' data2.txt
|
| 分支 | 根据地址或模式跳转到脚本中的指定位置 |
sed '{/First/b jump1 ; s/Line/Replacement/ ; :jump1 ; s/Line/Jump Replacement/}' data2.txt
|
| 测试 | 根据替换命令的结果跳转到指定标签 |
sed '{s/First/Matched/ ; t ; s/Line/Replacement/}' data2.txt
|
| 模式替换 |
使用
&
引用匹配的模式,使用括号定义子字符串组件
|
sed 's/.at/"&"/g'
和
sed 's/\(Guide to\) Programming/\1 DevOps/'
|
通过这些技巧和应用场景的介绍,希望你能更好地掌握sed编辑器,在日常的文本处理工作中发挥其强大的功能。
超级会员免费看
91

被折叠的 条评论
为什么被折叠?



