1

I have these lines in multiple files:

<update>2013-02-10</update>
<version>1.15</version>

and I want to replace them with (new date and version):

<update>2019-06-30</update>
<version>1.28</version>

How can do this on multiple files using sed or awk? (I'm on Mac OS)

edit 1: lines <update> and <version> are not one after another and I want to replace every occurrence of them.

edit 2: date varies but the string <update>doesn't get changed, so I can't use find "2013-02-10" and replace with "new date"

  • Do the lines need to be together? Can you just replace all occurrences of <update>2013-02-10</update> and all occurrences of <version>1.15</version>, or do you need to only replace when they are found one after the other as you show? – terdon Jun 11 at 16:22
  • no, these lines are not together, I want to replace all occurrences of <update>2013-02-10</update> and all occurrences of <version>1.15</version> – kuruvi Jun 11 at 16:32
4
sed -i backup -E '/<update>/s/[0-9]{4}-[0-9]{2}-[0-9]{2}/2019-06-30/;/<version>/s/[0-9]\.[0-9]{1,2}/1.28/' *
  • -i backup means to edit the files at their place, but keep a backup file with extension backup. You can delete them if the command did what you expected. If it did something else you'll be happy to have the backups!
  • -E is for extended regular expressions. Makes the script more readable because you don't need to escape the {}
  • For each line with pattern /<update>/ do s/[0-9]{4}-[0-9]{2}-[0-9]{2}/2019-06-30/ which is replacing a date string ####-##-## with the given date
  • For each line with pattern /<version>/ do s/[0-9]\.[0-9]{1,2}/1.28/ which is replacing the version string #.# or #.## with the given version
  • Why are you matching all dates? That seems a little dangerous since there may be other dates that shouldn't be changed. – terdon Jun 11 at 18:07
  • As explained, only dates in lines with <update> get replaced. And the date may vary, so I need a mattern to match all date strings – Philippos Jun 11 at 18:10
  • Yes, but why are you assuming the OP would want to replace all dates? Maybe there are perfectly valid <updates> that shouldn't be replaced. Of course, the OP accepted, so you may well be right, it just seemed strange that you would make it so much more general. Especially since your command will change any line that contains <update> so not limited to lines matching <update>DATE</update>. – terdon Jun 11 at 18:13
  • See edit 2: date varies by the OP. So it needs to be general. You are right about the tags. XML would allow to have more stuff on the same line or have a line break between the tags or whatever. The usual risk when using a text processor on XML. s_<update>[0-9]{4}-[0-9]{2}-[0-9]{2}</update>_<update>2019-06-30</update>_ would reduce the risk, but not eliminate it. – Philippos Jun 11 at 18:21
  • Ah, yes, you're quite right. I had missed that edit! – terdon Jun 11 at 18:29
0

If you don't mind typing in two commands, you can use:

sed -i 's/\<update\>2013-02-10\<\/update\>/2019-06-30\<\/update\>/g' *

sed -i 's/\<version\>1.15/1.28\<\/version\>/g' *

In the home directory of where the files are.

Alternatively, if you want it to execute recursively:

find ./ -type f -exec sed -i 's/\<update\>2013-02-10/2019-06-30\<\/update\>/' {} \;

find ./ -type f -exec sed -i 's/\<version\>1.15/1.28\<\/version\>/' {} \;

  • 1
    1) Of course you can join several commands either by having them in different -e arguments or by joining them with a semicolon in one script (or on different lines) 2) I think BSD sed on MacOS requires an argument (backup extension or at least empty argument ("") 3) No need to escape < or >; they don't have a special meaning. Actually escaping them may break in future versions. – Philippos Jun 11 at 16:54

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.