regex 在引号中匹配文本(新手)

omvjsjqw  于 2023-10-22  发布在  其他
关注(0)|答案(5)|浏览(98)

我完全迷失在shell编程中,主要是因为我使用的每个网站都提供了不同的工具来进行模式匹配。所以我的问题是使用什么工具在管道流中进行简单的模式匹配。
上下文:我已经命名了.conf文件,我需要在一个简单的文件中的所有区域名称进行进一步处理。所以我做~$ cat named.local| grep zone和get totally完全lost丢失here.我的输出是~一百个左右的换行符,格式为“zone“domain.tld”{",我需要双引号中的文本。

1sbrub3j

1sbrub3j1#

我想你要找的是sed...它是一个流艾德编辑器,可以让你逐行替换。
正如您所解释的,命令`cat named.local| grep zone'会给你一个类似这样的输出:

zone "domain1.tld" {
zone "domain2.tld" {
zone "domain3.tld" {
zone "domain4.tld" {

我猜你希望输出像这样,因为你说你需要双引号中的文本:

"domain1.tld"
"domain2.tld"
"domain3.tld"
"domain4.tld"

因此,实际上,我们只需要每行中双引号之间的文本(包括双引号本身)。
我不确定您是否熟悉Regular Expressions,但对于编写shell脚本的任何人来说,它们都是非常宝贵的工具。例如,正则表达式/.o.e/将匹配任何第二个字母是小写o,第四个字母是e的单词。这将匹配包含“zone“、“tone“甚至“I am tone-deaf.”等单词的字符串。
这里的技巧是使用.(点)字符来表示“任何字母”。还有一些其他的特殊字符,比如*,意思是“重复前一个字符0次或更多次”。因此,像a*这样的正则表达式将匹配“a“、“aaaaaaa“或空字符串:“”
因此,您可以使用以下命令匹配引号内的字符串:/".*"/
关于sed,还有一件事你应该知道(根据评论,你已经知道了!))-它允许 * 回溯 *。一旦你告诉它如何识别一个单词,你就可以让它把这个单词作为替换的一部分。例如,假设你想打开这个列表:

Billy "The Kid" Smith
Jimmy "The Fish" Stuart
Chuck "The Man" Norris

进入此列表:

The Kid
The Fish
The Man

首先,您需要查找引号中的字符串。我们已经看到了,它是/".*"/
接下来,我们要使用引号中的内容。我们可以用parans来 group 它:/"(.*)"/
如果我们想用下划线替换引号中的文本,我们会执行替换:s/"(.*)"/_/,这将使我们得到:

Billy _ Smith
Jimmy _ Stuart
Chuck _ Norris

但我们有回溯!这将让我们回忆括号内的内容,使用符号\1。如果我们现在这样做:s/"(.*)"/\1/我们将得到:

Billy The Kid Smith
Jimmy The Fish Stuart
Chuck The Man Norris

因为引号不在括号里,所以它们不是\1的内容的一部分!
为了只保留双引号内的内容,我们需要匹配整行。为此,我们有^(表示“行的开始”)和$(表示“行的结束”)。
所以现在如果我们使用s/^.*"(.*)".*$/\1/,我们会得到:

The Kid
The Fish
The Man

为什么?让我们从左到右阅读正则表达式s/^.*"(.*)".*$/\1/

  • s/-启动一个替换正则表达式
  • ^-查找行的开头。从那里开始。
  • .*-继续,阅读每一个字符,直到.
  • " - ...直到出现双引号
  • (-开始一组a字符,我们可能希望在回溯时调用。
  • .*-继续,阅读每一个字符,直到.
  • ) -(pssst!关闭群组!)
  • " - ...直到出现双引号
  • .*-继续,阅读每个字符,直到.
  • $-线的尽头!
  • /-使用后面的内容替换匹配的内容
  • \1-粘贴匹配的第一个组的内容(括号中的内容)。
  • /-正则表达式的结尾

简单的英语:“阅读整行,复制双引号之间的文本。然后用两个qoutes之间的内容替换整行。”
您甚至可以在替换文本s/^.*"(.*)".*$/"\1"/周围添加双引号,因此我们将得到:

"The Kid"
"The Fish"
"The Man"

sed可以使用它来将该行替换为引号中的内容:

sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/"

(This只是用shell转义来处理双引号和斜杠之类的东西。)
所以整个命令应该是这样的:

cat named.local | grep zone | sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/"
7eumitmz

7eumitmz2#

好吧,还没有人提到cut,所以,为了证明有很多方法可以使用shell:

% grep '^zone' /etc/bind/named.conf  | cut -d' ' -f2
"gennic.net"
"generic-nic.net"
"dyn.generic-nic.net"
"langtag.net"
ymzxtsji

ymzxtsji3#

zoul@naima:etc$ cat named.conf | grep zone
zone "." IN {
zone "localhost" IN {
    file "localhost.zone";
zone "0.0.127.in-addr.arpa" IN {
zoul@naima:etc$ cat named.conf | grep ^zone
zone "." IN {
zone "localhost" IN {
zone "0.0.127.in-addr.arpa" IN {
zoul@naima:etc$ cat named.conf | grep ^zone | sed 's/.*"\([^"]*\)".*/\1/'
.
localhost
0.0.127.in-addr.arpa

正则表达式是.*"\([^"]*\)".*,它匹配:

  • 任意数量的任意字符:.*
  • 报价:"
  • 开始为以后的记忆:\(
  • 除引号外的任何字符:[^"]*
  • 结束组要记住:\)
  • 结束语:"
  • 和任意数量的字符:.*

当调用sed时,语法为's/what_to_match/what_to_replace_it_with/'。单引号的作用是防止regexp被bash扩展。当你用括号“记住”正则表达式中的某个东西时,你可以把它记为\1\2等。摆弄它一会儿。

ut6juiuv

ut6juiuv5#

只要有人指出sed/awk,我就要指出grep是多余的。

sed -ne '/^zone/{s/.*"\([^"]*\)".*/\1/;p}' /etc/bind/named.conf

这将显示您要查找的内容,但不包含引号(将引号移动到括号内以保留它们)。在awk中,使用引号更简单:

awk '/^zone/{print $2}' /etc/bind/named.conf

我尽量避免管道(但不是更多)。记住,Don't pipe cat。不需要了而且,由于awk和sed复制了grep的工作,所以也不要用管道连接grep。至少,不是sed或awk。
就我个人而言,我可能会使用Perl。但那是因为我可能已经完成了你在perl中所做的任何事情的其余部分,使其成为一个次要的细节(并且能够同时将整个文件和regex对所有内容进行处理,忽略\n's对于我不控制/etc/bind的情况来说是一个奖励,例如在共享的webhost上)。但是,如果我在shell中做这件事,上面两个中的一个将是我处理它的方式。

相关问题