awk find if specific line exists between multiple common patterns

拈花ヽ惹草 提交于 2020-01-06 14:38:28

问题


I cant quite get my statements working as I need.

I need to find if each of the patterns called Group contain the line FUNEnable within a config file. If its present then add a line after it within the file, if not then print a warning to screen. The could be any number of patterns called group as shown below:

Sample file

#config file
<Some config>
More config
</Some config>

#comment about FUNEnable
Other config things

<Group small.group>
Something here
FUNEnable
Funfile /someplace/afunfile
</Group>

<Group medium.group>
More stuff here
Funfile /someplace/afunfile
</Group>

First attempt:

cat configfile.conf | awk '/^<Group/,/^<\/Group>/' | grep -q ^'FUNEnable' || print "WARNING";

This works great if both patterns do not have SSLEnable but if one has SSLEnable present then it does not print the warning. I obviously need to build some form of loop into it but not quite sure

cat configfile.conf | awk -F /\n '/^<Group/,/^<\/Group>/ { if ($1 == "FUNEnable") {print $1 "\nANOTHER LINE"} else { print "WARNING"}}';

This doesnt quite do what i need.

Any pointers would be great.


回答1:


$ awk '/^<Group/{name=$2;missing=1} /FUNEnable/{missing=0} /^<\/Group/ && missing {print "FUNEnable missing for group <" name}' configfile.conf
FUNEnable missing for group <medium.group>

How it works:

  • /^<Group/{name=$2;missing=1}

    Every time that a new group is started, initialize the variable name to the group name and the variable missing to true (1).

  • /FUNEnable/{missing=0}

    Everytime that we encounter FUNEnable on a line, reset the variable missing to false (0).

  • /^<\/Group/ && missing {print "FUNEnable missing for group <" name}

    When we reach the end of a group and if missing is true, then print a warning.

The above was tested with GNU awk.




回答2:


Quick and dirty one-liner for what sounds like a quick and dirty task:

gawk -vRS='<Group' '!/\nFUNEnable.*<\/Group>/ && sub(/<\/Group>.*/,"") {print RS $0}'

Most of what it does is break the input into records separated with <Group and then echo out records that don't contain the right regex. You need GNU Awk to set RS to a multichar string.




回答3:


Store some state in your awk script.

awk '
BEGIN{ingroup = 0; found = 0;}
/begingroup/{ingroup = 1;}
$0 ~ /pattern/ && ingroup == 1{found = 1;}
/endgroup/ {if(found == 0) print "Pattern not found in group";
            found = 0; ingroup = 0;}'

In the above script, replace begingroup, pattern and endgroup with the corresponding regexes.




回答4:


This may work:

awk -F"\n" '{for (i=1;i<=NF;i++) if ($i~/^[ \t]*FUNEnable/) {f=1;$i=$i"\nNew line"}} 1; END  {if (!f) print "not found"} ' RS="" OFS="\n" ORS="\n\n" configfile.conf
#config file
<Some config>
More config
</Some config>

#comment about FUNEnable
Other config things

<Group small.group>
Something here
FUNEnable
New line
Funfile /someplace/afunfile
</Group>

<Group medium.group>
More stuff here
Funfile /someplace/afunfile
</Group>

If it finds a line starting with FUNEnable it adds a new line after it.
If it's not found it prints not found at end of file.


Some more readable:

awk '
    {
    for (i=1;i<=NF;i++) 
        if ($i~/^[ \t]*FUNEnable/) {
            f=1
            $i=$i"\nNew line"}} 
1
END  {
    if (!f) print "not found"} 
' FS="\n" RS="" OFS="\n" ORS="\n\n" configfile.conf


来源:https://stackoverflow.com/questions/27475262/awk-find-if-specific-line-exists-between-multiple-common-patterns

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!