红联Linux门户
Linux帮助

基础指南:利用Sed Stream编辑器在Linux中处理文本

发布时间:2017-04-08 09:38:48来源:zstack.org.cn作者:zstack_org
Sed stream编辑器是一款文本编辑器,能够对来自标准输入或文件的信息者编辑操作。Sed以非交互方式对内容逐行编辑。
这意味着大家能够通过调用命令做出编辑决定,而sed则能够自动加以执行。虽然这一机制不太直观且较难理解,但却是一种非常强大且快速的文本转换方式。
本教程将介绍多种基本操作,同时介绍与编辑器操作相关的必要语法。 Sed的作用并非替代常规文本编辑器,但大家应当将其作为一款卓越的文本编辑工具。
 
基本使用方式
总体而言,sed负责对读取自标准输入或文件的文本流进行操作。
意味着大家可以将其它命令的输出结果直接发送至sed进行编辑,或者利用它处理已经创建完成的文件。
需要强调的是,sed在默认条件下以标准方式进行输出。这意味着除非重新定义,否则sed将始终将结果输出至屏幕上,而非将其保存为文件。
其基本使用方式为:
sed [options] commands [file-to-edit]
为了进行编辑练习,这里我们将把部分文件复制至主目录当中。
cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .
我们使用sed查看这里复制完成的BSD许可文件。
由于sed会将其结果默认输出至屏幕,因此我们可以直接利用它(不加任何编辑命令)作为文件阅读器:
sed '' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
...
...
这一效果是因为我们在sed编辑命令中使用了单引号。由于未填写任何其它内容,因此其直接输出来自标准输出结果中的每行内容。
下面来看如何利用sed中的“cat”命令利用标准输入内容实现同样的结果。
cat BSD | sed ''
Copyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
如大家所见,我们可以轻松操作文件或者文本流(使用‘|’字符)。
 
输出行
在上一实例中,我们看到可以在不加任何操作的前提下,将输入结果发送至sed以直接输出标准结果。
下面我们了解sed的“print”命令,其在单引号内使用“p”字符。
sed 'p' BSD
Copyright (c) The Regents of the University of California.
Copyright (c) The Regents of the University of California.
All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
modification, are permitted provided that the following conditions
are met:
are met:
. . .
. . .
可以看到,sed将其中的每行内容输出了两次。这是因为其会自动输出每一行,而我们使用“p”命令则会再次执行print操作。
如上所示,sed首先输出两次第一行内容,再显示两次第二行内容。这意味着它接收一行,执行输出操作,且在重复下一行操作之前确保显示全部结果。
我们可以在sed中使用“-n”选项,其能够关闭自动输出功能:
sed -n 'p' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
现在我们再次实现每次输出一行的效果。
 
地址范围
说到这里,我们还没有提到什么与编辑相关的功能。接下来,我们来了解如何利用sed输出第一行以修改输出结果。
sed -n '1p' BSD
Copyright (c) The Regents of the University of California.By placing the number "1" before the print command, we have told sed the line number to operate on. We can just as easily print five lines (don't forget the "-n").
sed -n '1,5p' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
我们为sed提供了地址范围。如果我们向sed提供一条地址,则其只会在对应行处执行命令。在本示例中,我们要求sed输出第1到第5行。我们还可以使用其它指定方式,即首先提供地址,而后使用偏移告知sed处理哪些额外行:
sed -n '1,+4p' BSD
这条命令会给出同样的输出结果,因为我们告知sed从第1行开始,而后输出接下来4行。
如果我们希望进行隔行输出,则可在“~”字符后指定具体间隔。以下命令将自第1行开始,输出隔行内容:
sed -n '1~2p' BSD
Copyright (c) The Regents of the University of California.
modification, are permitted provided that the following conditions
1. Redistributions of source code must retain the above copyright
2. Redistributions in binary form must reproduce the above copyright
documentation and/or other materials provided with the distribution.
may be used to endorse or promote products derived from this software
. . .
. . .
 
删除文本
只需将之前提到的“p”命令改为“d”命令,即可轻松实现删除操作。
在删除命令中不需要使用“-n”命令,sed将输出一切未被删除的结果。
只要对上一节中使用的命令稍加修改,即可实现隔行内容删除。
sed '1~2d' BSD
All rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
without specific prior written permission.
. . .
. . .
需要注意的是,我们的源文件其实并未受到影响。该文件仍然完好无损,命令只编辑输出结果。
如果我们希望保存编辑结果,则可通过以下命令将标准输出结果重新定向至文件:
sed '1~2d' BSD > everyother.txt
如果我们利用cat命令打开文件,我们将看到与之前相同的输出结果。Sed在默认情况下不会编辑源文件内容。
我们可以添加“-i”选项变更这一操作方式,意味着对文件内容进行实际修改。
下面尝试编辑刚刚创建完成的“everyother.txt”文件,具体操作为删除文件中的隔行内容:
sed -i '1~2d' everyother.txt
再次使用cat命令,则可看到文件内容已经发生了变化。
如上的,“-i”选项可能非常危险!幸运的是,sed能够在编辑之前创建备份文件。
要在编辑前创建备份文件,直接在“-i”选项后添加备份后缀:
sed -i.bak '1~2d' everyother.txt
这条命令将创建一个“.bak”后缀备份文件,而后再对本体文件进行编辑。
 
替换文本
也许最为知名的sed使用方式就是替换文本。Sed能够利用正则表达式搜索文本模式,而后对原始内容进行替换。
作为最简单的格式,大家可以利用以下语法将某一单词替换为另一单词:
's/old_word/new_word/'
其中的“s”代表substitute命令。三个斜杠(/)用于划分不同文本字段。大家也可以使用其它字符实现字段分隔。
例如,如果我们打算变更某一网站名称,则须多使用一个分隔符——因为URL本身亦包含斜杠。我们将使用echo命令:
echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'
http://www.example.org/home.html
别忘记最后一个分隔符,否则sed会出现错误。
echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
sed: -e expression #1, char 22: unterminated `s' command
下面创建一个文件以进行内容替换:
echo "this is the song that never ends
yes, it goes on and on, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because..." > annoying.txt
现在让我们利用“forward”替换“on”。
sed 's/on/forward/' annoying.txt
this is the sforwardg that never ends
yes, it goes forward and on, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
这里有几点需要强调。首先,我们替换的是模式,而非单词。即将“song”中的“on”替换为“forward”。
另外需要注意的是第2行,第二个“on”并未被替换为“forward”。
这是因为在默认情况下,“s”命令只会匹配每行中的第一项模式,而后即前往下一行。
为了让sed正确替换每一行中的“on”,我们可以在substitute命令中使用一条可选标记。
在这里,我们在命令末尾使用“g”标记。
sed 's/on/forward/g' annoying.txt
this is the sforwardg that never ends
yes, it goes forward and forward, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
现在substitute命令会变更每项实例。
如果我们只希望对每行中的第二个“on”实例做出变更,那么我们可以使用“2”来替换“g”。
sed 's/on/forward/2' annoying.txt
this is the song that never ends
yes, it goes on and forward, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because...
如果我们只希望查看被替换的行,则可使用“-n”选项。
接下来,我们可以在substitute命令中使用“p”标记以输出替换行。
sed -n 's/on/forward/2p' annoying.text
yes, it goes on and forward, my friend
如大家所见,我们可以在命令末尾结合更多标记。
如果大家希望在搜索中忽略操作,则可添加“i”标记。
sed 's/SINGING/saying/i' annoying.txt
this is the song that never ends
yes, it goes on and on, my friend
some people started saying it
not knowing what it was
and they'll continue saying it forever
just because...
 
引用匹配的文本
如果我们希望利用正则表达式找出更为复杂的模式,我们可以通过多种方式从替换文本内引用匹配的文本。
例如,如果我们希望匹配从每行开头到“at”部分的内容,则可使用以下表达式:
sed 's/^.*at/REPLACED/' annoying.txt
REPLACED never ends
yes, it goes on and on, my friend
some people started singing it
REPLACED it was
and they'll continue singing it forever
just because...
可以看到,通配符表达式匹配到从每行开头到最后一个“at”的位置。
由于大家并不了解搜索字符串内所匹配的确切短语,因此可以使用“&”字符来代表所匹配文本。
以下示例展示了如何为所匹配文本部分添加括号:
sed 's/^.*at/(&)/' annoying.txt
(this is the song that) never ends
yes, it goes on and on, my friend
some people started singing it
(not knowing what) it was
and they'll continue singing it forever
just because...
我们还可以选择另一种更为灵活的匹配文本引用方式,即使用反斜杠加括号。
每一组由括号标记的搜索文本组都可利用反斜杠数字进行引用。例如,第一个括号组可以“\1”进行引用,第二组则为“\2”,以此类推。
在本示例中,我们将切换每行的前两个单词:
sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' annoying.txt
is this the song that never ends
yes, goes it on and on, my friend
people some started singing it
knowing not what it was
they and'll continue singing it forever
because just...
如大家所见,结果并不理想。例如,第二行直接路过了第一个单词,因为其中包含未被字符集列出的字符。同样,其在第五行中将“they’ll”当成了第二个单词。
下面对正则表达式的准确性进行调整:
sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' annoying.txt
is this the song that never ends
it yes, goes on and on, my friend
people some started singing it
knowing not what it was
they'll and continue singing it forever
because... just
这一次结果就好多了,标点与单词得到正确关联。
请注意,我们在标点当中重复了表达式(一次不加‘’字符,下一次加‘’字符)。这是因为“*”字符能够对它之前的字符集进行零次或多次匹配。
这意味着如果找不到模式,则与通配符相匹配的内容会被视为“匹配”。
为了确保至少找到一项模式,我们应当首先不使用通配符进行一次匹配,而后再加入通配符。
 
总结
到这里,我们已经对sed的基本使用方法以及如何快速调整sed命令进行了了解。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/29825.html