Editing config file via a bash script

30,395

Solution 1

The best way depends on whether you expect the file to be also modified by humans, how complex the file is, and whether you want your script to take precedence if it looks like someone else wants a different value. That is, if the file already contains DBPassword=swordfish, do you want to keep that, or replace it by DBPassword=password?

A common way of dealing with this is to have a section of the file delimited by “magic comments”, and only edit the part between these comments. Here's a way to do this with awk. If the magic comments are not present, the new section is added at the end of the file. Warning: untested code.

begin_marker='# BEGIN AUTOMATICALLY EDITED PART, DO NOT EDIT'
end_marker='# END AUTOMATICALLY EDITED PART'
new_section='DBHost=localhost
DBName=database
DBPassword=password'
export begin_marker end_marker
awk <file.conf >file.conf.new -v begin_marker="$begin_marker" -v begin_marker="$end_marker" -v new_section="$new_section" '
    1 {print}
    $0 == begin_marker && !changed {
        do {getline} while ($0 != end_marker); # discard old section content
        print new_section;
        print;
        changed = 1;
    }
    END {if (!changed) {print begin_marker; print new_section; print end_marker;}}
'
ln -f file.conf file.conf.old
mv -f file.conf.new file.conf

This approach doesn't work well if the program that reads the configuration file doesn't support multiple lines setting the same configuration item. In that case, you'll really need to remove the old ones. In this case I would advise leaving the comments untouched and adding your own settings at the end.

grep -vE '^[[:blank:]]*(DBHost|DBName|DBPassword)=$' <file.conf >file.conf.new
cat <<EOF >>file.conf.new
DBHost=localhost
DBName=database
DBPassword=password
EOF
ln -f file.conf file.conf.old
mv -f file.conf.new file.conf

Solution 2

I'll go with "ex" in silent mode:

ex -s $CONFIG_FILE << END_CMDS
%s/^#.DBHost/DBHOST/
%s/DBName=test/DBName=database/
%s/^#.DBPassword/DBPassword/
w!
q
END_CMDS

terdon's sed command is compact and efficient. But the interaction of a "here document" full of ex commands and shell string interpolation can be powerful. For example, the password could be substituted as the value of a shell variable:

%s/^#.DBPassword=password/DBPassword=$PASSWORD/

If you use vi or vim and you're familiar with the ':' mode, adding new/better/different edits is also quite easy.

Solution 3

If that is all you need, you could do something like

sed  -i.bak -e 's/DBName=.*/DBName=database/' \
 -e 's/#* *DBHost=.*/DBHost=localhost/' \
 -e 's/#* *DBPassword=.*/DBPassword=password/' config.file

This will copy the original config.file to config.file.bak and make the necessary changes.

Share:
30,395
Jacob
Author by

Jacob

Updated on September 18, 2022

Comments

  • Jacob
    Jacob over 1 year

    I've been trying to write a simple bash script which I'll be using to install an application and update it's config file. I'm having hard time to have get it's config file modified.

    # DBHost=localhost
    DBName=test
    # DBPassword=
    

    any suggestions how I can get above modified as below?

    DBHost=localhost
    DBName=database
    DBPassword=password
    
    • bigjosh
      bigjosh almost 9 years
      I can't believe we have to write error prone regular expressions just to do this very common task. There really should be a standardized tool like "update_config test.confg -uncomment_if_pressent DBHost=localhost".
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 11 years
    While ex is powerful, it's difficult to recover from errors (e.g. when an expected line is missing). Here you can get away without any conditional behavior, but this doesn't generalize so well.
  • rubo77
    rubo77 almost 8 years
    Did you test this code? or is it still untested?
  • rubo77
    rubo77 almost 8 years
    Other great examples here: stackoverflow.com/questions/5955548/…