I have a file that I want to update relatively frequently.
What needs to be done is that a specific part of the file would be changed to include some more lines. I am doing it with sed and \a option:
So this works:

sed -i "/import:/a\$IMPORTED" file  

This works as expected the first time. On the next re-runs this commands appends over and over the same lines.
How would I approach this so that I somehow remove everything I imported before I run it again?
E.g. use some following lines to anchor in the beginning that I know were not added automatically or something like that?

  • How do you know when the old $IMPORTED ends? – Jeff Schaller Nov 27 '18 at 20:42
  • @JeffSchaller:I know the format of the lines I add. And also I could consider the following line as an anchor but that would be error prone in case it changed – Jim Nov 27 '18 at 21:32
  • @don_crissti: I don't know that except that I kind of know the format of what I insert – Jim Nov 27 '18 at 21:33
  • @don_crissti: The added lines have a specific prefix: e.g. foo/bar/etc. But I am not sure if there won't be any other addition that wasn't done by sed. – Jim Nov 27 '18 at 21:50
  • 1
    sed can delete lines, no problem. So if you know those comments are always only on inserted lines, delete those lines e.g. \|// auto-lines|d – don_crissti Nov 27 '18 at 22:27

Your command:

sed "/import:/a\$IMPORTED" infile

Is inserting the literal $IMPORTED text on linux and GNU sed. The problem is that the shell is interpreting the backslash before the $. You can either quote correctly:

sed '/import:/a\'"$IMPORTED" infile

Or, split the value in its own script part:

sed -e '/import:/a\' -e "$IMPORTED" infile

It is always better to single quote sed scripts.

To replace an old value with a new one that may contain an undefined number of lines, you need to

  • First: capture all lines in the pattern space:

    sed 'H;1h;$!d;x' infile

  • Set values to change:

    old='original' new='newvalue'

  • Remove old value (which must exist):

    sed -E -e 'H;1h;$!d;x' -e 's/(import:)(\n)'"$old"'/\1/g' infile

  • Add the new input:

    sed -E -e 'H;1h;$!d;x' -e 's/(import:)(\n)'"$old"'/\1/g' -e 's/(import:)/\1\n'"$new"'/g' infile

There is an corner issue in that if the variable $old contains a null value (empty) a newline will gets removed. To solve that we need:

sed -E -e 'H;1h;$!d;x' -e 's/(import:)'"${old:+"(\\n)$old"}"'/\1/g' -e 's/(import:)/\1\n'"$new"'/g' infile
  • 1) I need to add remove the existing importing and add/refresh the new ones 2) Why is single quoting better? 3) I don't really understand the snippet. Could you please elaborate what's happening there? – Jim Nov 28 '18 at 19:03
  • (1)and(3) I'll try. (2) Because it avoids the interpretation of backslash (and other characters like $, !, etc.) by the shell which change what sed receives as commands. – Isaac Nov 28 '18 at 23:03

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.