2009-04-27 61 views
5

我在shell编程中完全迷失了,主要是因为我使用的每个站点都提供了不同的工具来进行模式匹配。所以我的问题是使用什么工具在管道流中进行简单模式匹配。匹配文本引号(新手)

上下文:我有named.conf文件,我需要在一个简单文件中的所有区域名称作进一步处理。所以我做〜$ cat named.local | grep区,并在这里完全失去。我的输出是〜百个左右的换行符,形式为“zone”domain.tld“{”,我需要双引号文本。

感谢您展示一种方法来做到这一点。

Ĵ

回答

23

我想你要找的是sed ...这是一个小号 tream itor这将让你在一行接一行的基础上做的替代品。

正如你解释它,命令`cat named.local | grep的区域”给你一个输出有点像这样:

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 

首先,你会寻找引号内的字符串。我们已经看到,这是/".*"/

接下来,我们要使用引号内的内容。我们可以它使用括号:/"(.*)"/

如果我们想替换用下划线引号的文本,我们会做一个替换: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/ - 启动替代正则表达式
  • ^ - 寻找该行的开始。从那里开始。
  • .* - 继续阅读每个字符,直到...
  • " - ...直到您达到双引号。
  • ( - 开始一组我们可能想在回溯后回想的角色。
  • .* - 继续下去,阅读每一个字符,直到...
  • ) - (!pssst关闭组)
  • " - ...直到你到达一个双引号。
  • .* - 继续下去,阅读每一个字符,直到...
  • $ - 行的结束!

  • / - 使用后,这是什么来代替你匹配

  • \1 - 粘贴相匹配的第一组(什么是在括号)的内容。
  • / - 正则表达式

在纯英文的结束:“读整条生产线,复制抛开双引号之间的文本,然后替换为双qoutes之间的内容整条生产线。“

您甚至可以添加双引号周围的替换文本s/^.*"(.*)".*$/"\1"/,所以我们会得到:

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

并能由sed用于替换从引号内内容的行:

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

(这只是壳逃出来处理双引号和斜线之类的东西。)

所以整个命令WO可能是这样的:

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

是的,我现在使用它,但我认为应该有更简单的方法来做到这一点,因为现在我使用sed -e's/zone“// g'| sed -e's /”{ // g'删除文件的开头和结尾,而不是仅仅匹配中间。 – jpou 2009-04-27 07:23:29

1

1.

[email protected]:etc$ cat named.conf | grep zone 
zone "." IN { 
zone "localhost" IN { 
    file "localhost.zone"; 
zone "0.0.127.in-addr.arpa" IN { 

2.

[email protected]:etc$ cat named.conf | grep ^zone 
zone "." IN { 
zone "localhost" IN { 
zone "0.0.127.in-addr.arpa" IN { 

3.

[email protected]:etc$ cat named.conf | grep ^zone | sed 's/.*"\([^"]*\)".*/\1/' 
. 
localhost 
0.0.127.in-addr.arpa 

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

  1. 任意数量的任何字符:.*
    • 报价:"
    • 开始记住购买:\(
    • 除了引用的任何字符:[^"]*
    • 结束组要记住:\)
    • 闭引号:"
    • 和任意数量的字符:.*

当调用sed,语法是's/what_to_match/what_to_replace_it_with/'。单引号是为了让您的正则表达式不会被bash扩大。当你使用parens“记住”正则表达式中的某些东西时,可以将它记忆为\1,\2等。用它来捣鼓一段时间。

2

嘛,没有人提到cut还,所以,证明有很多方法可以做一些与外壳:

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

只要有人指出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中完成所有其他的工作,使其成为一个小细节(并且能够同时处理所有文件和正则表达式,而忽略\ n对于哪些情况会是一种奖励。我不控制/ etc/bind,比如在一个共享的虚拟主机上)。但是,如果我是用壳做的话,上面两个中的一个就是我接近它的方式。