0

The following awk syntax will add the 3 lines in the file before the line with the word - 'DatePattern':

$ awk 'done != 1 && /DatePattern/ {
    print "log4j.appender.DRFA=org.apache.log4j.RollingFileAppender"
    print "log4j.appender.DRFA.MaxBackupIndex=100"
    print "log4j.appender.DRFA.MaxFileSize=10MB"
    done = 1
    } 1' file >newfile && mv newfile file

the problem is that awk does not care if the lines already exist, so what needs to be added to the awk, in order to insert the lines only if lines are not already present?

Other example

In this case we want to add before the line with word 'HOTEL' the names 'trump', 'bush', & 'putin', but only in the case where the names do not exists:

$ awk 'done != 1 && /HOTEL/ {
    print "trump"
    print "bush"
    print "putin"
    done = 1
    } 1' file >newfile && mv newfile file
slm
  • 363,520
  • 117
  • 767
  • 871
yael
  • 12,598
  • 51
  • 169
  • 303
  • Something like perl -pi -e 's/(?!putin\n)(HOTEL)/$1trump\nbush\nputin$2/g' file – user1133275 Aug 06 '18 at 16:55
  • I've seen this question surface a number of times. I wrote a fully POSIX compliant answer to it on the vi/Vim stack exchange: [How to append some line at the end of the file only if it's not there yet?](https://vi.stackexchange.com/a/6248/4676) – Wildcard Aug 07 '18 at 01:37
  • Also related: https://vi.stackexchange.com/q/6269/4676 and https://unix.stackexchange.com/a/257913/135943 – Wildcard Aug 07 '18 at 01:41
  • Exists none of the names? Any constraints on the names' order? – RudiC Aug 07 '18 at 10:19

2 Answers2

1

You could do this as follows:

# store the 3 lines to match in shell variables
line_1="log4j.appender.DRFA=org.apache.log4j.RollingFileAppender"
line_2="log4j.appender.DRFA.MaxBackupIndex=100"
line_3="log4j.appender.DRFA.MaxFileSize=10MB"

# function that escapes it's first argument to make it palatable
# for use in `sed` editor's `s///` command's left-hand side argument
esc() {
    printf '%s\n' "$1" | sed -e 's:[][\/.^$*]:\\&:g'
}

# escape the lines
line_1_esc=$(esc "$line_1")
line_2_esc=$(esc "$line_2")
line_3_esc=$(esc "$line_3")

# invoke `sed` and fill up the pattern space with 4 lines (rather than the default 1)
# then apply the regex to detect the presence of the lines 1/2/3.
sed -e '
    1N;2N;$!N
    '"/^$line_1_esc\n$line_2_esc\n$line_3_esc\n.*DatePattern/"'!D
    :a;n;$!ba
' input.file
Rakesh Sharma
  • 755
  • 4
  • 3
0

Based on the assumption that the order of the names doesn't matter, and they would occur always in a pack of three, try

awk '
BEGIN           {INSTXT = "trump" ORS "bush" ORS "putin"
                 for (n = split (INSTXT, T, ORS); n; n--) PRES[T[n]]
                }

!(LAST in PRES) &&
/HOTEL/         {print INSTXT
                }

                {LAST = $0
                }
1
' file
RudiC
  • 8,889
  • 2
  • 10
  • 22