Jamess
Jamess

Reputation: 113

Search and modify using sed in bash script

I am trying to edit a postgres configuration file using script

I would like to search if

listen_addresses = '*' already present or not. If already present, do nothing and if the exact string is not present, add the entry using following rule

If there is any configuration line with listen_addresses but with any other value that '*' exists, then I need to comment the line with a comment Commented out on DD-MM-YYYY by XYZ and then add a new line listen_addresses = '*' followed by a comment

Added on DD-MM-YYYY by XYZ

What I tried is some thing like this:

sed -i 's/^#?listen_addresses .*/listen_addresses = '*'/'  /etc/postgresql/9.3/main/postgresql.conf

But that do not help adding the comments and will insert only listen_addresses = * due to missing escape characters.

I could not figure out how to accomplish this change.

Upvotes: 1

Views: 1650

Answers (2)

TessellatingHeckler
TessellatingHeckler

Reputation: 28963

  • If it doesn't exist, you want to start by commenting it out? Sounds like a contradiction, but eh.

  • Any line starting with listen_addresses with any other value - Matching "[this] not followed by [that]" needs a negative lookahead, which sed regexes don't support.

  • sed processes line by line, which makes it difficult to search the entire file and then decide whether to make changes.

This will be much easier if you either:

a) Comment out every listen_address = line, regardless of whether it's correct, then always add a new one to the end of the file:

sed -i "s/^\(listen_addresses .*\)/# Commented out by Name YYYY-MM-DD \1/" postgresql.conf
echo "listen_addresses = '*'" >> postgresql.conf

That would get annoying if you run this script regularly, as the file would grow and grow forever.

or

b) Use tools other than sed. But you haven't said you have any other tools available. Grep would make it easier, Perl even easier. But sticking with sed (and bash), what about a variation on the above:

# Comment out every listen_address line:
sed -i "s/^\(listen_addresses .*\)/#\1 Commented out by Name YYYY-MM-DD/" postgresql.conf

# Try to uncomment a correct one:
sed -i "s/^#\(listen_addresses = '\*'\).*/\1/" postgresql.conf

# Check if the correct one exists, and if it doesn't, add it:
if ! sed -n -e "/^listen_addresses = '\*'/!ba;Q0;:a;\$Q1" postgresql.conf ; then
  echo "listen_addresses = '*'" >> postgresql.conf
fi

Edit

OK, the constrained sed only was fun, but this is more straightforward logic and adds the new line just after a commented one.

#!/bin/env bash

if grep -q "^listen_addresses = '\*'" postgresql.conf ; then
    echo "Correct listen_addresses found, doing nothing"
    exit
fi

if ! grep -q "^listen_addresses =.*" postgresql.conf ; then
    echo "No listen_addresses found, adding one at the end"
    echo "listen_addresses = '*'" >> postgresql.conf
    exit
fi

if grep -q "^listen_addresses =.*" postgresql.conf ; then
    echo "Wrong listen_addresses found, commenting them out"
    sed -i "s/^\(listen_addresses.*\)/#\1 Commented out by Name YYYY-MM-DD/" postgresql.conf

    echo "Adding correct one"
    sed -i "/^#listen_addresses/a listen_addresses = '\*'" postgresql.conf
fi

Upvotes: 5

anubhava
anubhava

Reputation: 784958

In shell you cannot nest single quote inside single quotes. Also use double quote for using shell variables in sed.

Try this sed:

comment="commented on $(date)"
sed -i "s~^#?listen_addresses .*~listen_addresses = '*'\n$comment~" /etc/postgresql/9.3/main/postgresql.conf

Upvotes: 2

Related Questions