Search code examples
bashshellsednsregularexpression

Find the pattern (YYYY-MM-DD) and replace it with the same value concatenating with apostrophes


I have this kind of data:

1,1990-01-01,2,A,2015-02-09 
1,NULL,2,A,2015-02-09
1,1990-01-01,2,A,NULL

And looking for solution which will replace each date in the file with the old value but adding apostrophes. Basically expected result from the example will be:

1,'1990-01-01',2,A,'2015-02-09' 
1,NULL,2,A,'2015-02-09'
1,'1990-01-01',2,A,NULL

I have found the way how to find the pattern which match my date, but still can't get with what I can then replace it.

sed 's/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/????/' a.txt > b.txt

Solution

  • Catch the date in a group by surrounding the pattern with parentheses (). Then you can use this catched group with \1 (second group would be \2 etc.).

    sed "s/\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\)/'\1'/g"
    

    Note the g at the end, which ensures that all matches are replaced (if there are more than one in one line).


    If you add -r switch to sed, the awkward backslashes before () can be omitted:

    sed -r "s/([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])/'\1'/g"
    

    This can be further simplified using quantifiers:

    sed -r "s/([0-9]{4}-[0-9]{2}-[0-9]{2})/'\1'/g"
    

    Or even:

    sed -r "s/([0-9]{4}-([0-9]{2}){2})/'\1'/g"
    

    As mentioned in the comments: Also, in this particular case, you may use & instead of \1, which matches the whole looked-up expression, and omit the ():

    sed -r "s/[0-9]{4}(-[0-9]{2}){2}/'&'/g"