我完全迷失在shell编程中,主要是因为我使用的每个网站都提供了不同的工具来进行模式匹配。所以我的问题是使用什么工具在管道流中进行简单的模式匹配。上下文:我已经命名了.conf文件,我需要在一个简单的文件中的所有区域名称进行进一步处理。所以我做~$ cat named.local| grep zone和get totally完全lost丢失here.我的输出是~一百个左右的换行符,格式为“zone“domain.tld”{",我需要双引号中的文本。
1sbrub3j1#
我想你要找的是sed...它是一个流艾德编辑器,可以让你逐行替换。正如您所解释的,命令`cat named.local| grep zone'会给你一个类似这样的输出:
sed
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,还有一件事你应该知道(根据评论,你已经知道了!))-它允许 * 回溯 *。一旦你告诉它如何识别一个单词,你就可以让它把这个单词作为替换的一部分。例如,假设你想打开这个列表:
/.o.e/
o
e
zone
tone
I am tone-deaf.
.
*
a*
a
aaaaaaa
/".*"/
Billy "The Kid" Smith Jimmy "The Fish" Stuart Chuck "The Man" Norris
进入此列表:
The Kid The Fish The Man
首先,您需要查找引号中的字符串。我们已经看到了,它是/".*"/。接下来,我们要使用引号中的内容。我们可以用parans来 group 它:/"(.*)"/如果我们想用下划线替换引号中的文本,我们会执行替换:s/"(.*)"/_/,这将使我们得到:
/"(.*)"/
s/"(.*)"/_/
Billy _ Smith Jimmy _ Stuart Chuck _ Norris
但我们有回溯!这将让我们回忆括号内的内容,使用符号\1。如果我们现在这样做:s/"(.*)"/\1/我们将得到:
\1
s/"(.*)"/\1/
Billy The Kid Smith Jimmy The Fish Stuart Chuck The Man Norris
因为引号不在括号里,所以它们不是\1的内容的一部分!为了只保留双引号内的内容,我们需要匹配整行。为此,我们有^(表示“行的开始”)和$(表示“行的结束”)。所以现在如果我们使用s/^.*"(.*)".*$/\1/,我们会得到:
^
$
s/^.*"(.*)".*$/\1/
为什么?让我们从左到右阅读正则表达式s/^.*"(.*)".*$/\1/:
s/
.*
"
(
)
/
简单的英语:“阅读整行,复制双引号之间的文本。然后用两个qoutes之间的内容替换整行。”您甚至可以在替换文本s/^.*"(.*)".*$/"\1"/周围添加双引号,因此我们将得到:
s/^.*"(.*)".*$/"\1"/
"The Kid" "The Fish" "The Man"
sed可以使用它来将该行替换为引号中的内容:
sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/"
(This只是用shell转义来处理双引号和斜杠之类的东西。)所以整个命令应该是这样的:
cat named.local | grep zone | sed -e "s/^.*\"\(.*\)\".*$/\"\1\"/"
7eumitmz2#
好吧,还没有人提到cut,所以,为了证明有很多方法可以使用shell:
cut
% grep '^zone' /etc/bind/named.conf | cut -d' ' -f2 "gennic.net" "generic-nic.net" "dyn.generic-nic.net" "langtag.net"
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等。摆弄它一会儿。
's/what_to_match/what_to_replace_it_with/'
bash
\2
3okqufwl4#
你应该看看awk。
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中做这件事,上面两个中的一个将是我处理它的方式。
5条答案
按热度按时间1sbrub3j1#
我想你要找的是
sed
...它是一个流艾德编辑器,可以让你逐行替换。正如您所解释的,命令`cat named.local| grep zone'会给你一个类似这样的输出:
我猜你希望输出像这样,因为你说你需要双引号中的文本:
因此,实际上,我们只需要每行中双引号之间的文本(包括双引号本身)。
我不确定您是否熟悉Regular Expressions,但对于编写shell脚本的任何人来说,它们都是非常宝贵的工具。例如,正则表达式
/.o.e/
将匹配任何第二个字母是小写o
,第四个字母是e
的单词。这将匹配包含“zone
“、“tone
“甚至“I am tone-deaf.
”等单词的字符串。这里的技巧是使用
.
(点)字符来表示“任何字母”。还有一些其他的特殊字符,比如*
,意思是“重复前一个字符0次或更多次”。因此,像a*
这样的正则表达式将匹配“a
“、“aaaaaaa
“或空字符串:“”因此,您可以使用以下命令匹配引号内的字符串:
/".*"/
关于
sed
,还有一件事你应该知道(根据评论,你已经知道了!))-它允许 * 回溯 *。一旦你告诉它如何识别一个单词,你就可以让它把这个单词作为替换的一部分。例如,假设你想打开这个列表:进入此列表:
首先,您需要查找引号中的字符串。我们已经看到了,它是
/".*"/
。接下来,我们要使用引号中的内容。我们可以用parans来 group 它:
/"(.*)"/
如果我们想用下划线替换引号中的文本,我们会执行替换:
s/"(.*)"/_/
,这将使我们得到:但我们有回溯!这将让我们回忆括号内的内容,使用符号
\1
。如果我们现在这样做:s/"(.*)"/\1/
我们将得到:因为引号不在括号里,所以它们不是
\1
的内容的一部分!为了只保留双引号内的内容,我们需要匹配整行。为此,我们有
^
(表示“行的开始”)和$
(表示“行的结束”)。所以现在如果我们使用
s/^.*"(.*)".*$/\1/
,我们会得到:为什么?让我们从左到右阅读正则表达式
s/^.*"(.*)".*$/\1/
:s/
-启动一个替换正则表达式^
-查找行的开头。从那里开始。.*
-继续,阅读每一个字符,直到."
- ...直到出现双引号(
-开始一组a字符,我们可能希望在回溯时调用。.*
-继续,阅读每一个字符,直到.)
-(pssst!关闭群组!)"
- ...直到出现双引号.*
-继续,阅读每个字符,直到.$
-线的尽头!/
-使用后面的内容替换匹配的内容\1
-粘贴匹配的第一个组的内容(括号中的内容)。/
-正则表达式的结尾简单的英语:“阅读整行,复制双引号之间的文本。然后用两个qoutes之间的内容替换整行。”
您甚至可以在替换文本
s/^.*"(.*)".*$/"\1"/
周围添加双引号,因此我们将得到:sed
可以使用它来将该行替换为引号中的内容:(This只是用shell转义来处理双引号和斜杠之类的东西。)
所以整个命令应该是这样的:
7eumitmz2#
好吧,还没有人提到
cut
,所以,为了证明有很多方法可以使用shell:ymzxtsji3#
正则表达式是
.*"\([^"]*\)".*
,它匹配:.*
"
\(
[^"]*
\)
"
.*
当调用
sed
时,语法为's/what_to_match/what_to_replace_it_with/'
。单引号的作用是防止regexp被bash
扩展。当你用括号“记住”正则表达式中的某个东西时,你可以把它记为\1
、\2
等。摆弄它一会儿。3okqufwl4#
你应该看看awk。
ut6juiuv5#
只要有人指出sed/awk,我就要指出grep是多余的。
这将显示您要查找的内容,但不包含引号(将引号移动到括号内以保留它们)。在awk中,使用引号更简单:
我尽量避免管道(但不是更多)。记住,Don't pipe cat。不需要了而且,由于awk和sed复制了grep的工作,所以也不要用管道连接grep。至少,不是sed或awk。
就我个人而言,我可能会使用Perl。但那是因为我可能已经完成了你在perl中所做的任何事情的其余部分,使其成为一个次要的细节(并且能够同时将整个文件和regex对所有内容进行处理,忽略\n's对于我不控制/etc/bind的情况来说是一个奖励,例如在共享的webhost上)。但是,如果我在shell中做这件事,上面两个中的一个将是我处理它的方式。