4

I know sed can replace a piece of string within a text file like this :

sed -i 's/oldstring/newstring/g' test.txt

But, how do I replace the line if it exists and automatically add it on a new line if it doesn't exist?

Thanks.

Edit : Thank you for your responses. As per the requests on your comments and answer, here's more details :

  • I want to check the existence of the old string and replace it with the new string if it exists.
  • I want to add the new string in a new line at the end of the txt file if the old string does not exist
  • If there are multiple occurances of the same string, it would be an error since its a config file.The other occurances can be removed after replacing the first occurance.
  • 2
    Add it in a new line where? At the end of the doc? – muru Nov 21 '15 at 10:11
  • 1
    Check existence of old or new string or both? Add old or new string? – Sadi Nov 21 '15 at 10:51
9

One way to do this it to bring grep into the equation. First check whether the file contains the string with a quick grep and then append or substitute accordingly:

grep -q string file && 
    sed -i 's/string/newstring/' file || echo "newstring" >> file

The above is a shorthand way of writing:

if grep -q string file; then 
    sed -i 's/string/newstring/' file
else
    echo "newstring" >> file
fi

Personally, however, I would use perl for this instead. Just read the file once and set a variable to 1 if the substitution was made. Then, at the end, add the string if the variable is not 1:

perl -lpe '$i=1 if s/oldstring/newstring/; 
           END{print "newstring" if $i!=1;}' file > tmpfile && mv tmpfile file
  • 1
    @kos yes, the END{} is executed after the file has been closed so it won't work. – terdon Nov 21 '15 at 12:01
  • Thanks for the nice shorthand, but wouldn't it be better to use printf "\nnewstring" as echo "newstring" seems to append it to the last (non-empty) line? On the other hand, using printf "\n..." leaves an empty line above when there's already an empty line at the end. Any better solution for this? – Sadi Nov 21 '15 at 15:41
  • @Sadi no, echo foo >> file will add foo in a new line. So will printf 'foo\n' >> file. – terdon Nov 22 '15 at 0:06
  • I also thought so but when I tested on this occasion in a new text file ending with a non-empty line (i.e. no empty line at the end of the file) the command echo foo >> file always appended "foo" to that last non-empty line and added an empty line after that, so it's apparently inserting "foo\n" instead of "\nfoo" then (Ubuntu 15.10). I'll further check this issue... – Sadi Nov 22 '15 at 8:33
  • @Sadi that's different. The >> operator appends to the end of the file. Normally, the last character of a text file is \n so it will append the text after the \n and make a new line. If you know your file doesn't end with a \n, you would have to use printf '\nfoo\n' >> file, yes. If you need to deal with such cases, please edit your question and make it clear. – terdon Nov 22 '15 at 13:08
2

This should achieve what is required:

grep -q "oldstring" test.txt
if [ $? -eq 1 ]; then
    echo "newstring" >> test.txt
else
    sed -i 's/oldstring/newstring/g' test.txt
fi
  • @kos : Thank you for the UUOC award ( : - D ) and for taking the time to teach something to this beginner in shell scripting. I'll now try to improve the code above. – Sadi Nov 21 '15 at 11:33
  • 1
    I didn't really mean to "award" it to you, just to point that out. :D. Looks better, you could also shorten the if / else check to this single line: [ $? -eq 1 ] && echo "newstring" >> test.txt || sed -i 's/oldstring/newstring/g' test.txt. – kos Nov 21 '15 at 11:47
1

Using AWK:

<<<"$(<in)" awk '{if(/foo/){x=sub(/foo/, "bar", $0)};print}END{if(x!=1){print "bar"}}' >in
% cat in1
string oldstring string
% cat in2
string foo string
% <<<"$(<in1)" awk '{if(/oldstring/){x=sub(/oldstring/, "newstring", $0)};print}END{if(x!=1){print "newstring"}}' >in1
user@user-X550CL ~/tmp % cat in1
string newstring string
% <<<"$(<in2)" awk '{if(/oldstring/){x=sub(/oldstring/, "newstring", $0)};print}END{if(x!=1){print "newstring"}}' >in2
% cat in2
string foo string
newstring

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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