Sunday, January 28, 2024

[SOLVED] How do I insert conditional text before the first match?

Issue

sed "/^.*#location/n;/.*location/i 0000" myfile

Find a location that does not start with a comment and insert 0000 in front of it the first time it matches.

What did I do wrong?

I 4 hours try some answers from google, try combine, but nothing changed.

For example this: sed to insert on first match only

I try add like this:

sed "0,/^.*#location/n;/.*location/i 0000" myfile

or this:

sed "/^.*#location/n;0,/.*location/i 0000" myfile

and this:

sed "/^.*#location/n;/.*location/i 0000\n&/0" myfile

Input:

server {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}

Output:

server {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    0000

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}



Input:

server {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    location 73347347 {
        proxy_pass 123;
    }

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}

Output:

server {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    0000

    location 73347347 {
        proxy_pass 123;
    }

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}


Solution

Using GNU awk for the 3rd arg to match():

$ awk '!done && match($0,/^([[:space:]]*)location/,a){print a[1] "0000" ORS; done=1} 1' file
server {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    0000

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}

or using any POSIX awk:

$ awk '!done && match($0,/^([[:space:]]*)location/){new=$0; sub(/[^[:space:]].*/,"0000",new); print new ORS; done=1} 1' fileserver {

    #location /api/graphql {
    #       modsecurity off;
    #       proxy_pass http://10.1.0.4;
    #}

    0000

    location 123 {
        proxy_pass 123;
    }

    location / {
            modsecurity off;
            proxy_pass http://10.1.0.4;
    }

}

Regarding "What did I do wrong?" - sed's great for doing s/old/new/ on individual lines but for anything else, just use awk for clarity, simplicty, etc.



Answered By - Ed Morton
Answer Checked By - Dawn Plyler (WPSolving Volunteer)