Search code examples
awksed

How do I insert conditional text before the first match?


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.