Using POSIX sed for infile substitution

Posted on Oct 5, 2019

Something I learned when I started writing tools for developers in companies is that there’s GNU sed, BSD sed and that they are not compatible for something that I tend to write a lot: infile substitution.

I would find myself doing conditionals, finding out if it was running in a Darwin/BSD or if it was running on Linux. Then there was the bit where some people would install gnu-sed from Homebrew in their macs and add the gnubin path to their $PATH which then would break my conditionals because they would be using GNU sed in which I thought were BSD sed.

This made really hard building scripts that would work both in all developers machines and deployment servers.

In goes POSIX sed. So there’s a “standard” which not many people limits itself to use, because using -i is too convenient, which BSD and GNU both implement yet differently (one requires -i '' the other either -i or -i'' so both implementations are incompatible between themselves). But POSIX sed only has -e, -f and -n.

So easy, right? Let’s just do a sed and pipe it out to the same file:

sed -e "s/foo/bar/" "filename" > "filename"

Done. Is it? No! If you check the content of the file it will be blank. So you need to create a temp file, modify it and then remove the temp file:

sed -e "s/foo/bar/" "filename" > "filename.tmp"
mv "filename.tmp" "filename"

So it’s basically your call to decide if you can write an extra line of code on your scripts or write a whole logic to figure out what sed is being used and if it should be -i or -i ''.