带终端:使用正则表达式II:替换

在我自己 以前的文章 我已在基本级别上告诉您正则表达式的每个最常用特殊字符的工作方式。 使用这些正则表达式,可以在文本文件或其他命令的输出中执行复杂的搜索。 在本文中,我将解释如何使用sed命令以比仅将一个文本更改为另一文本更为有效的方式来查找和替换文本。

有关grep命令的更多信息

在开始讨论sed之前,我想先对grep命令进行一些评论,以完成上一篇文章中所解释的内容。 我要说的所有内容也与此相关。 稍后我们将看到它与搜索之间的关系。

结合正则表达式

我在上一篇文章中讨论的许多特殊字符不仅可以与其他字符结合使用,而且可以与整个正则表达式结合使用。 执行此操作的方法是使用括号形成一个子表达式。 让我们来看一个例子。 让我们从下载可用于测试的文本开始。 这是短语列表。 为此,我们将使用以下命令:

curl http://artigoo.com/lista-de-frases-comparativas-comicas 2>/dev/null | sed -n 's/.*\(.*\.\)<\/p>/\1/gp' > frases

 这将使您留在启动名为“ phrases”的文件的目录中。 您可以打开它看看并笑一点。 🙂

现在,让我们假设我们要查找具有6个单词的短语。 困难在于形成与每个单词匹配的正则表达式。 单词是字母序列,可以是大写或小写,类似于 '[a-zA-Z]+',但您还必须指定这些字母必须用字母以外的其他字符分隔,也就是说, '[a-zA-Z]+[^a-zA-Z]+'。 请记住:括号内的第一个字符“ ^”表示我们要与不在范围内的字符匹配,“ +”表示一个或多个字符。

我们已经有一个可以匹配单词的正则表达式。 要将其与6配对,必须重复6次。 为此,我们使用了键,但是放了没用 '[a-zA-Z]+[^a-zA-Z]+{6}',因为6会重复正则表达式的最后一部分,而我们要重复全部,所以我们要输入的是: '([a-zA-Z]+[^a-zA-Z]+){6}'。 用括号我们形成一个子表达式,用括号将我们重复6次。 现在,您只需要在前面添加“ ^”,在后面添加“ $”以匹配整行。 命令如下:

grep -E '^([a-zA-Z]+[^a-zA-Z]+){6}$' frases

结果就是我们想要的:

它比玛卡莲娜歌唱得更多。 您比路易斯·阿奎莱(LuisAguilé)更精干。 您的文化比石头少。 您知道比CañitaBrava更多的语言了。 他的皱纹比图坦·卡蒙(TutanKhamón)多。 您对Ramba的了解少于Rambo。

注意,我们放置-E参数是因为我们想使用扩展的正则表达式来使“ +”工作。 如果使用基本的,则必须转义括号和大括号。

反向引用或反向引用

如果您安装了拼写检查器,则可能会有一个单词列表 /usr/share/dict/words。 如果没有,您可以使用以下命令将其安装在arch中:

sudo pacman -S words

或在debian中使用:

sudo aptitude install dictionaries-common

如果需要,可以查看该文件以查看其包含的单词。 实际上,它是指向发行版所用语言的Word文件的链接。 您可以同时安装多个Word文件。

我们将使用该文件。 事实证明,我们很想知道那里所有的七个字母回文。 对于那些不知道的人:回文是一个大写的单词,即可以从左到右以及从右到左读取。 让我们尝试以下命令:

grep '^\(.\)\(.\)\(.\).\3\2\1$' /usr/share/dict/words

看起来有点奇怪,对吧? 如果我们尝试一下,结果将取决于您发行版的语言和列表中的单词,但就我而言,对于西班牙语,结果是这样的:

苯胺苯胺滚

让我们看看这个正则表达式是如何工作的。

除了“ ^”和“ $”(我们已经知道它的用途)以外,我们在左边看到的第一件事是用圆括号括起来的三组点。 不要将每个括号前面的横条弄糊涂了。 因为我们使用的是基本的正则表达式,所以它们要避开括号,但是它们没有其他含义。 重要的是我们要求带点的任何三个字符,但是每个点都用括号括起来。 这是为了保存与这些点匹配的字符,以便可以从正则表达式中再次引用它们。 这是括号的另一种用法,稍后会在进行替换时派上用场。

这是下面三个数字前面带有斜杠的地方。 在这种情况下,限制很重要。 它用于指示以下数字是反向引用,并且是指前面的括号之一。 例如:\ 1表示第一个括号,\ 2表示第二个括号,依此类推。

也就是说,使用我们放置的正则表达式,我们要查找的所有单词都以任何四个字母开头,然后具有与第三个字母相同的字母,另一个与第二个字母相同,另一个与相同。第一。 结果就是单词列表中的七个字母的回文。 正如我们想要的。

如果我们使用扩展的正则表达式,则不必逃避括号,但是对于扩展的正则表达式,后向引用并不是在所有程序中都有效,因为它们不是标准化的。 但是,使用grep可以起作用,因此这可能是另一种方法。 您可以根据需要尝试。

替换表达式:sed命令

除了搜索之外,正则表达式的最佳用途之一是替换复杂的文本。 为此,一种方法是使用sed命令。 sed命令的功能远不止于替换文本,但在这里我将使用它。 我将在此命令中使用的语法如下:

sed [-r] 's/REGEX/REPL/g' FICHERO

或者:

COMANDO | sed [-r] 's/REGEX/REPL/g'

其中REGEX将是搜索正则表达式,而REPL将是替换正则表达式。 请记住,此命令并没有真正替换我们指示的文件中的任何内容,但是它所做的是向我们显示了终端中替换的结果,因此请不要担心接下来要输入的命令。 它们都不会修改系统上的任何文件。

让我们从一个简单的例子开始。 我们在/ etc目录中都有各种配置文件,这些配置文件通常带有以“#”开头的注释。 假设我们要查看其中一个没有注释的文件。 例如,我将使用fstab进行此操作。 您可以尝试使用想要的那个。

sed 's/#.*//g' /etc/fstab

我不会将命令的结果放在这里,因为它取决于fstab中的内容,但是如果将命令的输出与文件的内容进行比较,您会发现所有注释都消失了。

在此命令中,搜索表达式为«#.*“,那是一个”#“,后跟任意数量的字符,即注释。 还有替换表达式,如果您连续查看两个小节,您会发现它们都不存在,因此它所做的就是不添加任何注释,即删除它们。 更简单的不可能。

现在我们要做相反的事情。 假设我们要注释文件的所有行。 让我们这样尝试:

sed 's/^/# /g' /etc/fstab

您将看到,在命令的输出中,所有行均以井号和空格开头。 我们所做的是将行的开头替换为«# «。 这也是一个非常简单的示例,其中要替换的文本始终相同,但是现在我们要使其复杂一些。

替换的好处是,在替换表达式中,您可以使用反向引用,就像我之前告诉您的那样。 让我们回到本文开头下载的词组文件。 我们将所有的大写字母括在括号中,但是我们将使用以下命令:

sed 's/\([A-Z]\)/(\1)/g' frases

我们这里所拥有的是替换表达式中的反向引用,该反向引用引用了搜索表达式中的括号。 替换表达式中的括号是普通括号。 在替换表达式中,它们没有特殊含义,它们按原样放置。 结果是所有大写字母都被相同的字母替换,无论它是什么,并带有括号。

替换表达式中还可以使用另一个字符,它是“&”,并且被搜索表达式匹配的所有文本替换。 例如,可以将文件中的所有短语都用引号引起来。 这可以通过以下命令来实现:

sed 's/.*/"&"/g' frases

该命令的操作与上一个命令非常相似,只是现在我们替换的是整行,并在同一行加上引号。 由于我们使用的是“&”,因此不必放在括号中。

一些有用的带有正则表达式的命令

这里有一些我觉得有用或好奇的命令,它们使用正则表达式。 使用这些命令,正则表达式的实用性比到目前为止提供的示例要好得多,但是对我来说,解释一些有关正则表达式的工作方式以理解它们似乎很重要。

  • 显示手册页的各个部分:

man bash | grep '^[A-Z][A-Z ]*$'

当然,您可以将bash命令更改为所需的任何内容。 然后,从男人那里,您可以直接使用正则表达式转到您感兴趣的部分。 按«/»开始搜索并编写«^ALIASES$»例如,转到“别名”部分。 我认为这是几年前我开始使用正则表达式的第一个用途。 没有这样的技巧,几乎不可能浏览手册的某些页面。

  • 显示机器所有用户的名称,包括特殊用户的名称:

sed 's/\([^:]*\).*/\1/' /etc/passwd

  • 显示用户名,但仅显示具有shell的用户名:

grep -vE '(/false|/nologin)$' /etc/passwd | sed 's/\([^:]*\).*/\1/g'

确实可以使用单个正则表达式来完成,但是实现的方式超出了我在这些文章中告诉您的内容,因此我通过组合两个命令来完成。

  • 在数字文件中所有数字的最后三位数字前插入逗号:

sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers

它仅适用于最多6位数字的数字,但可以多次调用以将分隔符放置在其他三位数的组中。

  •  从文件中提取所有电子邮件地址:

grep -E '\<[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\>' FICHERO

  • 分隔文件中出现的所有日期的日,月和年:

sed -r 's/([0-9]{2})[/-]([0-9]{2})[/-]([0-9]{4})/Día: \1, Mes: \2, Año: \3/g' FICHERO

  • 找出我们的本地IP:

/sbin/ifconfig | grep 'inet .*broadcast' | sed -r 's/[^0-9]*(([0-9]+\.){3}[0-9]+).*/\1/g'

也可以使用单个sed命令来完成此操作,但为简便起见,我最好将其分为grep和sed。

一些有用的地址

以下是一些与正则表达式有关的有用地址:

  • 正则表达式库:这是一个正则表达式库,您可以在其中搜索与您感兴趣的主题相关的正则表达式。 搜索网址,ID或其他内容。
  • 正则表达式:在线正则表达式检查器。 它允许您输入文本并对其应用正则表达式,以进行搜索或替换。 它提供有关正则表达式的信息,您可以选择一些选项来更改其行为。
  • 正则表达式测试器:它是Firefox的附加组件,可让您从浏览器中检查正则表达式。

结论

现在仅此而已。 正则表达式很复杂,但很有用。 学习它们需要时间,但是如果您像我一样,和他们一起玩似乎很有趣,并且您会一点一点地掌握它们。 这是整个世界。 关于惰性量词,PERL风格的正则表达式,多行等,还有很多话要说。 然后,每个程序都有其特性和其变体,因此,我能为您提供的最佳建议是,每次必须在新程序中编写正则表达式时,始终查看所使用程序的文档。

嘿! …嘿! … 醒来! …你们都在睡觉吗? 🙂

来源

我从这里摘录了本文中一些正则表达式的想法和示例:


发表您的评论

您的电子邮件地址将不会被发表。 必填字段标有 *

*

*

  1. 负责数据:MiguelÁngelGatón
  2. 数据用途:控制垃圾邮件,注释管理。
  3. 合法性:您的同意
  4. 数据通讯:除非有法律义务,否则不会将数据传达给第三方。
  5. 数据存储:Occentus Networks(EU)托管的数据库
  6. 权利:您可以随时限制,恢复和删除您的信息。

  1.   拉夫

    精通!

    1.    赫格堡

      还不错,但是非常感谢。 希望人们喜欢它。 🙂

      1.    奥斯卡

        我喜欢哈!

        1.    赫格堡

          那我一定做对了。 大声笑!! 🙂

          非常感谢您的评论。

          1.    布莱尔·帕斯卡

            他妈的继续写人,继续努力。

          2.    赫格堡

            @Blaire Pascal:像您这样的评论鼓励它。 🙂非常感谢!

      2.    城市

        我也喜欢它...谢谢🙂

        1.    赫格堡

          感谢您的评论。 我希望多写一些。 🙂

  2.   玛丽安

    您的帖子太棒了,您学到了很多东西,而您学会了以一种优雅而有效的方式执行任务。

    您是否考虑过收集所有Shell脚本文章? 归类为pdf将是一本很好的手册。

    振作起来,非常感谢您!

    1.    赫格堡

      非常感谢!! 这不是一个坏主意。 目前只有两个,但是我稍后会考虑。 🙂

  3.   基约夫

    很好的文章,超过5条。

    1.    赫格堡

      谢谢。 很高兴您喜欢它。 🙂

  4.   塞巴斯蒂安

    优秀的! 我需要更改以下表达式,但我不知道该怎么做:
    192.168.0.138/服务器通过192.168.0.111/data
    问题出在“ /”符号上。
    我正在使用命令:
    找。 -name“ * .txt” -exec sed -i's / TEXT1 / TEXT2 / g'{} \;
    用来轻松地执行此类任务的工具,但我不能...
    有人知道我应该怎么做吗?
    拥抱!
    西巴

    1.    赫格堡

      您要做的就是逃避这样的角色:

      找。 -name“ * .txt” -exec sed -i's / \ /服务器/ \ / data / g'{} \;

      您也可以在sed中使用另一个分隔符。 它不一定是酒吧。 sed允许使用任何字符。 例如,这将更加清楚:

      找。 -name“ * .txt” -exec sed -i's | / Server | / data | g'{} \;

      而且,如果您要复制并粘贴此注释中的命令,请注意引号,wordpress会将其更改为印刷用的。 🙂

      问候。

  5.   塞巴斯蒂安

    优秀的!!!!
    我一直在寻找这种解决方案很长时间。
    在这里,我将保留使用的完整命令

    找。 -name“ * .txt” -exec sed -i's | 192 \ .168 \ .0 \ .238 \ /服务器| 192 \ .168 \ .0 \ .111 \ /数据| g'{} \;

    此命令的优点是它以递归方式更改所有.txt文件(或所需的扩展名)...您必须非常小心!
    但这是非常有用的!

    好吧,感谢您所做的一切,并向整个小组表示祝贺。
    我总是从邮件中阅读它们!
    拥抱
    西巴