Stuart Naylor
Stuart Naylor

Reputation: 43

Sed insert line multiple times on pattern

I have

/var/log/syslog
{
    rotate 7
    daily
    missingok
    notifempty
    delaycompress
    compress
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/mail.log
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
    rotate 4
    weekly
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

What I want to do is insert olddir /var/log/oldlog a line before the top rotate 7 and lower rotate 4 lines. Is it possible to make sed do possible multiple insertions? Also it also needs to ignore the rotate > pattern in the postrotate.

I thought I would ask before I try and do something longwinded and horrid. Also the above is the main question but a secondary one would be to iterate all files in the directory with the above.

Any pointers would be really appreciated

Upvotes: 1

Views: 285

Answers (1)

Allan
Allan

Reputation: 12438

Input:

$ cat input_file
/var/log/syslog
{
    rotate 7
    daily
    missingok
    notifempty
    delaycompress
    compress
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/mail.log
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
    rotate 4
    weekly
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

Command:

sed -i.bak '/rotate [0-9]\+/{s@^\( \+\)@\1olddir /var/log/oldlog\n\1@}' input_file

Output:

$ cat input_file
/var/log/syslog
{
    olddir /var/log/oldlog
    rotate 7
    daily
    missingok
    notifempty
    delaycompress
    compress
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/mail.log
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
    olddir /var/log/oldlog
    rotate 4
    weekly
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        invoke-rc.d rsyslog rotate > /dev/null
    endscript
}

Explanations:

  • -i.bak will activate the option to take a backup of each file before modifying them and add the suffix .bak at the end of each filename.
  • /rotate [0-9]\+/ will only take the lines that contain rotate followed by a space and an integer
  • when sed encounters one of those lines, it will execute s@^\( \+\)@\1olddir /var/log/oldlog\n\1@ which is a find and replace command that will replace the beginning of the line as well as all the spaces by the pattern. I have taken into account the spaces to keep the indentation by using back reference \1.

2nd question:

find /path/to/my/files -type f -exec sed -i.bak '/rotate [0-9]\+/{s@^\( \+\)@\1olddir /var/log/oldlog\n\1@}' {} \;

You might add -name 'YOUR FILE PATTERN' if you want to reduce the find scope. Also consider using -maxdepth N to limit the depth in term of subdirs of the search

Update:

As the text contains a mix of \t and spaces, we can use the following POSIX class [:blank:] that will match those 2 characters.

Command:

sed -i.bak '/^[[:blank:]]*rotate[[:blank:]]\+[0-9]\+[[:blank:]]*$/{s@^\([[:blank:]]*\)@\1olddir /var/log/oldlog\n\1@}' input_file

Upvotes: 3

Related Questions