使用awk打印一个文本块直到第一个空白行

时间:2016-01-22 12:22:00

标签: regex awk sed

这是我的示例文件:

Host dns1
        HostName 172.20.4.75
        User root
        Port 22

我想只打印一个块意味着例如

Host: dns2  HostName: 172.20.4.80   User: root  Port: 22

输出:

Distinct

但是在这个示例中,所有块都有4行,可能会达到5行或更多行,所以我想从Host打印到第一个空行或从Host移到第一个空行

我对正则表达式非常不好,需要这个才能完成我的脚本

谢谢

5 个答案:

答案 0 :(得分:3)

我认为你基本上想要这个:

gulp taskname --option 123

取消设置记录分隔符,以便将每个块视为记录,然后打印与该模式匹配的记录。

或者使用shell变量:

awk -v RS='' '/dns1/' file

在这两个示例中,我使用的是默认操作为host=dns1 awk -v host="$host" -v RS='' '$0 ~ host' file 的事实。由于您可能会使用{ print }更改输出,因此您可能需要考虑添加{ printf ... }语句以避免不必要地处理文件的其余部分。

答案 1 :(得分:2)

类似的awk

$ awk -v RS= -v OFS=' ' '{for(i=1;i<NF;i+=2) $i=$i":"}1' hosts

Host: dns2 HostName: 172.20.4.80 User: root Port: 22
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
Host: dns5 HostName: 172.20.4.78 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22

将以所需的输出格式为您提供所有记录。您可以进一步过滤此输出或添加模式,例如

$ awk -v RS= -v OFS=' ' '{for(i=1;i<NF;i+=2) $i=$i":"} /dns2/' hosts

Host: dns2 HostName: 172.20.4.80 User: root Port: 22

如果要在处理选定记录后退出,则需要稍微更改脚本

$ awk -v RS= -v OFS=' ' '/dns2/{for(i=1;i<NF;i+=2) $i=$i":"; print; exit}' hosts
Host: dns2 HostName: 172.20.4.80 User: root Port: 22

如果要选择除一条记录以外的所有内容,可以否定该模式(并删除退出)

$ awk -v RS= -v OFS=' ' '!/dns2/{for(i=1;i<NF;i+=2) $i=$i":"; print}' hosts
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
Host: dns5 HostName: 172.20.4.78 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22

请注意,sed inplace replacement需要一个中间文件。如果要使用格式化的一个记录替换原始文件,可以在最后一个awk语句中使用此命令模式

$ awk ... > temp && mv temp original

更新: 设置OFS将更改字段之间的所有分隔符。您希望按name: value对它们进行逻辑分组,因此请更改脚本

$ awk -v RS= '{for(i=1;i<NF;i++) $i=$i (i%2?":":"\t")}1' hosts
Host: dns2       HostName: 172.20.4.80   User: root      Port: 22
Host: dns1       HostName: 172.20.4.75   User: root      Port: 22
Host: dns3       HostName: 172.20.4.76   User: root      Port: 22
Host: dns4       HostName: 172.20.4.77   User: root      Port: 22
Host: dns5       HostName: 172.20.4.78   User: root      Port: 22
Host: dns6       HostName: 172.20.4.79   User: root      Port: 22

在偶数定位字段后设置制表符分隔符。

答案 2 :(得分:1)

与Tom Fenech方法没有什么不同,因为它使用记录分隔符,但它也与字段分隔符一起使用以获得所需的输出:

awk -v RS='' -F'\n[\t ]*' -v OFS='  ' '/dns1/{$1=$1;print}' file

更改输出字段分隔符时,需要使用$1=$1 (或$0=$0或其他任何字段)来强制awk重新评估记录和考虑新的字段分隔符。

注意:当使用exit命令找到匹配的块时,您可以退出awk。这避免了处理文件的所有结尾。 您也只能使用第一个字段测试模式/dns1/

awk -v RS='' -F'\n[\t ]*' -v OFS='  ' '$1~/dns1/{$1=$1;print;exit}' file

如果在结果中添加分号,由于修改了字段,$1=$1技巧就变得无用了。你可以写:

awk -v RS='' -F'\n[\t ]*' -v OFS='  ' '$1~/dns1/{for(i=1;i<=NF;i++){sub(" ", ": ", $i)};print;exit}' file

答案 3 :(得分:1)

打印第3条记录:

$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' 'NR==3{$1=$1; gsub(/ +/,": "); print}' file
Host: dns3      HostName: 172.20.4.76   User: root      Port: 22

打印包含dns4的记录:

$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' '/dns4/{$1=$1; gsub(/ +/,": "); print}' file
Host: dns4      HostName: 172.20.4.77   User: root      Port: 22

打印除dns3dns4dns5以外的所有记录:

$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' '!/dns[345]/{$1=$1; gsub(/ +/,": "); print}' file
Host: dns2      HostName: 172.20.4.80   User: root      Port: 22
Host: dns1      HostName: 172.20.4.75   User: root      Port: 22
Host: dns6      HostName: 172.20.4.79   User: root      Port: 22

答案 4 :(得分:0)

这可能适合你(GNU sed):

 sed -n '/Host dns1/{:a;N;/^\s*$/M!ba;s/\n\s*/  /g;s/\s*$//p}' file

这将重点放在必需的字符串上,然后追加以下行直到空白行,最后操作收集到所需输出中的新字符串。