我有一个文本文件,其中包含以下内容。
$ cat hosts.yml
[prod_env]
foo.example.com
bar.example.com
[stage_env]
foo_stage.example.com
bar_stage.example.com
[dev_env]
foo_dev1.example.com
dev2_bar.example.com
我想过滤 bash 中 [prod_env] 文件下列出的主机。我以有限的知识尝试过 sed、awk 和 grep,但我不知道如何过滤它们。
示例:我想打印 prod_env 和 dev_env 下的主机。所以最终的输出将是:
foo.example.com
bar.example.com
foo_dev1.example.com
dev2_bar.example.com
答案1
解决方案sed
:
sed -nEe '/\[(prod|dev)_env]/!d;N;:loop' -e 's/.*\n//;${p;d;};N;P;/\n\[/D;bloop' hosts.yml
/\[(prod|dev)_env]/!d
删除所有行,直到找到[prod_env]
或[dev_env]
找到N;:loop
添加下一行并开始循环- 在循环内部,我们删除两行中的第一行
s/.*\n//
,因为它要么是该[...env]
行,要么我们已经在最后一个循环周期中打印了它 ${p;d;}
如果我们在打印时到达最后一行,则打印剩余的行N;P
添加下一行并打印当前行/\n\[/D
查看下一行是否以 开头[
。在这种情况下,缓冲区中的第一行(已打印)可以被丢弃,我们从该[
行开始bloop
否则循环
您可以逐行进行操作,而不是将下一行添加到缓冲区,打印并删除旧行,但这将需要另一个循环,因为您无法重新开始D
答案2
你可以(在 Mac 上):
tr "\n" "\t" < hosts.yml | sed $'s%\t\\[%\\\n\[%g' | grep 'prod\|dev' | sed $'s%.*\]\\\t%%g' | tr "\t" "\n"
tr
将把一切都放在一条线上- 第一个
sed
将在每个部分之前换行 grep
会剪出你想要的线条(部分)- 其次
sed
将删除 [] 部分。 - 最后
tr
将换行,以便每行获得一个主机名。
答案3
awk 'BEGIN{RS="[";FS="]\n"}
$1 ~/(prod|dev)_env/ {print $2}' ex1
答案4
您可以使用GNU sed
如下所示的方法来执行此操作:
$ sed -nEe '
/\[/!{H;$!d;}
x;1!s/^\[(prod|dev)_env]\n//p
' hosts.yml