linux – 只打印与grep匹配的一部分

我很感兴趣是否可以在以下情况下使用单个grep命令.

我有一个dhcpd.conf文件,其中定义了DHCP主机.给定主机名,我需要在dhcpd.conf文件中找到它的MAC地址.我需要使用它来禁用它的PXE启动配置,但这不是这个问题的一部分.

该文件的语法是统一的,但我仍然想让它变得有点傻瓜.以下是主机的定义方式:

    host client1 { hardware ethernet 12:23:34:56:78:89; fixed-address 192.168.1.11; filename "pxelinux.0"; }
    host client2 { hardware ethernet 23:34:45:56:67:78; fixed-address 192.168.1.12; filename "pxelinux.0"; }
    host client3 { hardware ethernet AB:CD:EF:01:23:45; fixed-address 192.168.1.13; filename "pxelinux.0"; }
    host client4 { hardware ethernet C1:CA:88:FA:F4:90; fixed-address 192.168.1.14; filename "pxelinux.0"; }

我们假设所有配置只占用一行,即使dhcpd.conf语法允许将选项分解为多行.但是,我们假设选项的顺序可能不同.

我想出了以下grep命令:

grep -o "^[^#]*host.*${DHCP_HOSTNAME}.*hardware ethernet.*..:..:..:..:..:..;" /etc/dhcp/dhcpd-hosts.conf

它应该忽略那些被注释的行,允许令牌之间的任意空格,并匹配到MAC地址的末尾.
当我运行它时,我得到这样的行:

host client1 { hardware ethernet 12:23:34:56:78:89;

这很棒!但重点是我只需要一个MAC地址,而不需要前面的垃圾箱.现在我知道使用另一个grep,或者cut或awk来从这个输出中仅删除MAC地址将是微不足道的.但我想知道,有没有办法使用单个grep命令来获得最终结果,而不必将此输出传输到另一个过滤器?显然我不能忽略模式的开头,因为我想得到一个特定的主机名,因此匹配“..:..:..:..:..:..”会给我所有的MAC地址.

再一次,我想要一个命令(不一定是grep),它只从文件中删除正确的MAC地址.因此,我对那些说“grep … | grep …”或“grep … | cut …”等的任何解决方案都不感兴趣.

当然,在实践中,如果我使用多个过滤器并管道它们,没有什么不好的事情,我只是好奇是否有可能用一个过滤器来解决.

我会将输出分配给变量.

最佳答案 您可以使用Perl单行匹配文件的每一行与具有适当捕获组的单个正则表达式匹配,并且对于与您匹配的每一行,您可以打印子匹配.

有几种方法可以将Perl用于此任务.我建议使用perl -ne {program}惯用法,它隐含地循环stdin行,并为每一行执行一行{program}一次,当前行作为$_特殊变量提供. (注意:-n选项不会导致$_的最终值在隐式循环的每次迭代结束时自动打印,这就是-p选项会执行的操作;也就是说,perl -pe {program} .)

以下是解决方案.请注意,我决定使用obscure -s选项传递目标主机名,这样可以在{program}参数之后解析变量赋值规范,类似于awk的-v选项. (使用-n选项传递正常的命令行参数是不可能的,因为隐式的while(<>){…}循环吞噬了文件名的所有这些参数,但是-s机制提供了一个很好的请参阅Is it possible to pass command-line arguments to @ARGV when using the -n or -p options?.)这种设计可以防止在{program}字符串本身中嵌入$DHCP_HOSTNAME变量,这允许我们单引号并保存一些(实际上是8个)反斜杠.

DHCP_HOSTNAME='client3';
perl -nse 'print($1) if m(^\s*host\s*$host\s*\{.*\bhardware\s*ethernet\s*(..:..:..:..:..:..));' -- -host="$DHCP_HOSTNAME" <dhcpd.cfg;
## AB:CD:EF:01:23:45

我经常更喜欢Perl,因为以下原因:

> Perl提供了一个完整的通用编程环境,而sed则更为有限.
> Perl在CPAN上有一个庞大的公共可用模块库,可以轻松安装,然后与-M {module}选项一起使用. sed不可扩展.
> Perl比sed具有更强大的正则表达式引擎,具有环绕声断言,回溯控制动词,正则表达式和替换Perl代码,更多选项和特殊转义,嵌入式组选项等.见perlre.
>与直觉相反,尽管Perl具有更高的复杂性,但由于其双通过程和高度优化的操作码实现,它通常比sed快得多.例如,见http://rc3.org/2014/08/28/surprisingly-perl-outperforms-sed-and-awk/.
>我经常发现等效的Perl实现比sed更直观,因为sed有一组更原始的命令来操作底层文本.

点赞