Monday, November 4, 2013

Add Lines After Matching the Expression Using Sed

www.unixbabuforum.inI need to add the following lines 4 after it matches the expression if [ "$EUID" = "0" ] 

export RAILS_ENV=production 
export PATH=/usr/local/sphinx/bin:/usr/local/bin:$PATH 
export MAGICK_HOME=/usr/local 
export DYLD_LIBRARY_PATH=/usr/local/lib 

in /etc/profile . 

How do I do it using sed ?

www.unixbabuforum.inHaving a string so full of special characters gives you a quoting headache in sed. I would probably use awk which has a string-match function called index(). 

If your file is small (and /etc/profile should be) awk can edit it in situ, and it can leave the file alone if there is no match. 

You really want to test this on a gash copy of the file. It reads a here document that contains: the filename; the pattern; and the insertions. 

This is UNTESTED. I read the whole file into memory, and remember all the line numbers where the pattern matched in a hash array. 

If there is any such line, it then writes the file back onto itself, stuffing in the new lines at each such line. 

This code is way overkill for this problem, but is a very expandable awk technique, for example in doing context-sensitive multi-line edits.

AWK='''
function Edit (fn, Local, j, k, txWas, n, Ix) {
    while ((getline < fn) > 0) {
        txWas[++j] = $0; if (index ($0, txPatt)) { ++n; Ix[j]; }
    }
    close (fn); if (! n) return;
    for (j = 1; j in txWas; j++) {
        print txWas[j] > fn;
        if (j in Ix) {
            for (k = 1; k in txAdd; k++) print txAdd[k] > fn;
        }
    }
    close (fn);
}
NR == 1 { fnEdit = $0; next; }
NR == 2 { txPatt = $0; next; }
NR >  2 { txAdd[++nAdd] = $0; }
END { Edit( fnEdit); }
'''
awk "${AWK}" <<'EOF'
/etc/profile
if [ "$EUID" = "0" ]
export RAILS_ENV=production
export PATH=/usr/local/sphinx/bin:/usr/local/bin:$PATH
export MAGICK_HOME=/usr/local
export DYLD_LIBRARY_PATH=/usr/local/lib
EOF

Actually, sed does let you quote all the special characters, and it does have an append command, but I can't recall how to do the escapes or do a multiline text or terminate it. Somebody will post it properly by the time this gets up there.


www.unixbabuforum.inSlight shortfall on the posting mechanism. Some backslashes got removed. 

In the string defining the pattern after PATT=, the left and right square brackets need a backslash just before them, just like the dollar sign has. This line may also have got folded - it should run through to the second single quote all on one line. 

Obviously the test case after Try this does not get backslashed - that is real test text, it in not being herded into a shell variable. 

Quoting is hard enough in shell, but even less predictable in this posting environment.
www.unixbabuforum.inThe issue is that the PATT is hard to make general-purpose - it has to be quoted for when it goes between the /../, so that is content-dependent. 

The awk version, on the other hand, is plain-text compliant. I don't know if it is obvious, but there are no hard strings in the awk - all the real stuff is read from stdin on the here doc. 

I thought of a couple of refinements for the awk. 

.. You could put in a list of filenames to have the edits applied to all of them. 

.. In fact, you could also define a list of patterns and have each one with a different replacement group. 

.. You could fix it to only substitute once, or only on the third match, or a bunch of other ideas.

0 comments:

Post a Comment

 
Design by BABU | Dedicated to grandfather | welcome to BABU-UNIX-FORUM