[英]Print a block of text until the first blank line using awk
这是我的示例文件:
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
例如,我只想打印一个块
Host dns1
HostName 172.20.4.75
User root
Port 22
输出:
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
但在此示例中,所有块都有4行,也许以后它们会达到5行或更多行,所以我想从主机打印到第一行或从主机删除到第一行
我真的对正则表达式不好,需要这个来完成我的脚本
谢谢
我认为您基本上想要这样:
awk -v RS='' '/dns1/' file
取消设置记录分隔符,以便将每个块都视为一条记录,然后打印与模式匹配的任何记录。
或使用shell变量:
host=dns1
awk -v host="$host" -v RS='' '$0 ~ host' file
在这两个示例中,我都使用默认操作为{ print }
的事实。 由于您可能会使用{ printf ... }
来更改输出,因此您可能要考虑添加一个exit
语句,以避免不必要地处理文件的其余部分。
类似的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就地替换需要一个中间文件。 如果要将原始文件替换为无一个记录的格式化文件,则可以在最后一个awk语句上使用此命令模式
$ awk ... > temp && mv temp original
更新:设置OFS
将更改字段之间的所有分隔符。 您想按name: value
逻辑对它们进行分组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
在偶数定位的字段之后设置制表符分隔符。
与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
要打印第三条记录:
$ 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
要打印所有包含dns3
, dns4
或dns5
记录,请dns4
以下dns5
:
$ 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
这可能对您有用(GNU sed):
sed -n '/Host dns1/{:a;N;/^\s*$/M!ba;s/\n\s*/ /g;s/\s*$//p}' file
这将重点放在所需的字符串上,然后追加以下几行直到空白为止,最后操作收集到所需输出中的新字符串。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.