I have a package that needs to add a text fragment, stored in fileA, to another file fileB. Due to the current requirements and the control I have over the file, I can make the assumption that if the first line of fileA is not present, the others won't be there, either. So this becomes a trivial two-liner:
if ! grep -q "$(head -1 fileA)" >/dev/null 2>&1; then cat fileA >> fileB fi
Now of course the tricky part is to remove those lines at the time the package is uninstalled. One approach would be:
Now this becomes tricky when other packages (or users) can manipulate fileB in the mean time, so there may be content following the last line of fileA that I do not want to remove.
So I tried to play around with diff(1) and patch(1), attempting to diff fileA fileB and then reverse apply the patch. But that doesn't work: the resulting patch describes how to create a file that only contains the lines from fileA or, alternatively, a way to add the lines from fileB. Not quite what I want.
I then attempted to rewrite the patch on the fly into the reverse of the same patch, ie an "unpatch". And that kind of worked:
diff fileA fileB | \ sed -e 's/^[0-9].*//' -e 's/^> //' -e '/./,/^$/!d'
But that seems rather silly. Another, more obvious approach would be to:
And guess what, our good friend sed(1) will happily do the right thing for us:
sed -e "/$(head -1 fileA)/,/$(tail -1 fileA)/d" fileB
You need double quotes to have the subshell expansion work. Add '/./,/^$/!d' to suppress multiple blank lines. And yes, this may break depending on the contents of fileA, for example if the first or last line contains a / (and which is why I actually did end up using the "unpatch" approach noted above). But it seemd entertaining enough at the time...
If you have a better or simpler way to do this (one-liner, please)...
March 2, 2012