1
votes

On Linux, I have a bash script in which I am using sed. In this script, I am using substitutions with "sed -i".

Unfortunately, on MacOS, this version of sed is not the same as Linux sed.

I am looking for a way to use a compatible sed on Linux and MacOS, i.e having the same script for both OS.

Could you tell me if using gsed for both OS instead of sed allows to have a unique compatible version for this script (where gsed -i works on both)

UPDATE 1 :

In my case, on MacOS 10.9.5, I would like to replace the line 2 of a file by the value of a variable. I tried :

a=2
sed -i'' -e "2c\$a" file.dat

but the line is replaced by "$a" and not the value of a=2.

Any idea ?

ps: I would like to get a Linux/MacOS portable command line.

1
Could you just not use the -i flag and do a mv -f your_sed_output your_original_file after your sed? then you don't have to monkey around with installs and prayers.JNevill
You can use sed -i.bak '....' and it will work same on both Lunux and MacOSanubhava
gsed on BSD (Darwin, MacOS) or Solaris for that matter would stand for GNU sed, which is the same as sed shipped with most Linux distributions. Unfortunately, I do not think that (all) Linux distributions would also have the g prefixed name (mine doesn't) for it (btw. same story awk, tar and others).Ondrej K.
Perl can do everything sed can do, and far more besides, and is more orthogonal and consistent between platforms, including Solaris too.Mark Setchell
How about sed -e "2s|.*|$a|" file.datMark Setchell

1 Answers

2
votes

There is unfortunately a large number of behaviors in sed which are not adequately standardized. It is hard to articulate a general answer which collects all of these.

For your specific question, a simple function wrapper like this should suffice.

sedi () {
    case $(uname -s) in
        *[Dd]arwin* | *BSD* ) sed -i '' "$@";;
        *) sed -i "$@";;
    esac
}

As you discovered, details of the c command are also poorly standardized. I would simply suggest

sedi "2s/.*/$a/" file.dat

where obviously use a different separator if $a could contain a slash; or if you are using Bash, use ${a//[\/]/\\/} to backslash all slashes in the value.

Other behaviors which differ between implementations include extended regex support (-r or -E or not available), the ability to pass in multiple script fragments with -e (the portable solution is to separate commands with newlines), the ability to pass standard input as the argument to -f, and the general syntax of several commands (does the filename argument of the r and w commands extend up to the next whitespace, semicolon, or newline? Can you put a command immediately adjacent to a brace? What are the precise semantics of backslashed newlines and where are they mandatory? Where are backslashes before command arguments mandatory?) and obviously regex flags and features.