back to listing index

Appending a line to a file only if it does not already exist

[web search]
Original source (stackoverflow.com)
Tags: bash one-liners if-not-exists
Clipped on: 2018-10-11

I need to add the following line to the end of a config file:

include "/configs/projectname.conf"

to a file called lighttpd.conf

I am looking into using sed to do this, but I can't work out how.

How would I only insert it if the line doesn't already exist?

asked Aug 24 '10 at 13:40
Benjamin Dell
7262812
up vote 186 down vote accepted

Just keep it simple :)

grep + echo should suffice:

grep -q -F 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar

Edit: incorporated @Cerin suggestion.

NOTE: for "editors" changing my answer: if you have an alternative solution give your own answer! Editing is intended for clarifying, formatting, better English and so on! Don't change the answer given by others! (thank you)

answered Aug 24 '10 at 13:53
drAlberT
12.6k42635

This would be a clean, readable and reusable solution using grep and echo to add a line to a file only if it doesn't already exist:

LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
answered Jan 19 '15 at 9:22
rubo77
7,6401271151
  • If it's to a file where you need root permissions: sudo grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee -a "$FILE" – nebffa Dec 8 '17 at 0:50
  • This actually doesn't work when the line starts with a -. – hyperknot Feb 6 at 22:03
  • @zsero: good point! I added -- in the grep command, so it will not interpret a $LINE starting with a dash as options any more. – rubo77 Feb 7 at 1:05

Here's a sed version:

sed -e '\|include "/configs/projectname.conf"|h; ${x;s/incl//;{g;t};a\' -e 'include "/configs/projectname.conf"' -e '}' file

If your string is in a variable:

string='include "/configs/projectname.conf"'
sed -e "\|$string|h; \${x;s|$string||;{g;t};a\\" -e "$string" -e "}" file
answered Aug 24 '10 at 19:04
Dennis Williamson
230k62304366
  • For a command that replaces a partial string with the complete/updated config file entry, or appends the line as needed: sed -i -e '\|session.*pam_mkhomedir.so|h; ${x;s/mkhomedir//;{g;tF};a\' -e 'session\trequired\tpam_mkhomedir.so umask=0022' -e '};:F;s/.*mkhomedir.*/session\trequired\tpam_mkhomedir.so umask=0022/g;' /etc/pam.d/common-session – bgStack15 May 31 '16 at 16:01
  • Nice, it helped me a lot +1. could you please, explain your sed expression ? – Rahul Jun 10 '16 at 10:39
  • I'd love to see an annotated explanation of this solution. I've used sed for years but mostly just the s command. The hold and pattern space swaps are beyond me. – nortally Jun 24 '16 at 15:50

If writing to a protected file, @drAlberT and @rubo77 's answers might not work for you since one can't sudo >>. A similarly simple solution, then, would be to use tee --append:

LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE"  || echo "$LINE" | sudo tee --append "$FILE"
answered Mar 31 '17 at 16:28
hamx0r
1,2351526

use awk

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file file
answered Aug 24 '10 at 14:05
ghostdog74
208k39207294

another sed solution is to always append it on the last line and delete a pre existing one.

sed -e '$a\' -e '<your-entry>' -e "/<your-entry-properly-escaped>/d"

"properly-escaped" means to put a regex that matches your entry, i.e. to escape all regex controlls from your actuall entry, i.e. to put a backslash infront of ^$/*?+().

this might fail on the last line of your file or if there's no tangling newline, I'm not sure, but that could be dealed with by some nifty branching...

answered May 8 '14 at 18:16
Robin479
756511
  • Nice one-liner, short and easy to read. Works great for updating etc/hosts: sed -i.bak -e '$a\' -e "$NEW_IP\t\t$HOST.domain\t$HOST" -e "/.*$HOST/d" /etc/hosts – Noam Manos Apr 26 at 16:38

If, one day, someone else have to deal with this code as "legacy code", then that person will be grateful if you write a less exoteric code, such as

grep -q -F 'include "/configs/projectname.conf"' lighttpd.conf
if [ $? -ne 0 ]; then
  echo 'include "/configs/projectname.conf"' >> lighttpd.conf
fi
answered May 1 at 23:54

I needed to edit a file with restricted write permissions so needed sudo. working from ghostdog74's answer and using a temp file:

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file > /tmp/file
sudo mv /tmp/file file
answered Apr 29 '14 at 14:44
webdevguy
800815

Your Answer

 
community wiki

Not the answer you're looking for? Browse other questions tagged or ask your own question.

asked

8 years, 1 month ago

viewed

55,911 times

active

1 month ago

Love this site?

Get the weekly newsletter! In it, you'll get:

  • The week's top questions and answers
  • Important community announcements
  • Questions that need answers

see an example newsletter

Hot Network Questions