Is there an invocation of sed
todo in-place editing without backups that works both on Linux and Mac? While the BSD sed
shipped with OS X seems to
If you need to do sed
in-place in a bash
script, and you do NOT want the in-place to result with .bkp files, and you have a way to detect the os (say, using ostype.sh), -- then the following hack with the bash
shell built-in eval
should work:
OSTYPE="$(bash ostype.sh)"
cat > myfile.txt <<"EOF"
1111
2222
EOF
if [ "$OSTYPE" == "osx" ]; then
ISED='-i ""'
else # $OSTYPE == linux64
ISED='-i""'
fi
eval sed $ISED 's/2222/bbbb/g' myfile.txt
ls
# GNU and OSX: still only myfile.txt there
cat myfile.txt
# GNU and OSX: both print:
# 1111
# bbbb
# NOTE:
# if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
# then you will get a backup file with quotations in the file name,
# - that is, `myfile.txt""`
The following works for me on Linux and OS X:
sed -i' ' <expr> <file>
e.g. for a file f
containing aaabbaaba
sed -i' ' 's/b/c/g' f
yields aaaccaaca
on both Linux and Mac. Note there is a quoted string containing a space, with no space between the -i
and the string. Single or double quotes both work.
On Linux I am using bash
version 4.3.11 under Ubuntu 14.04.4 and on the Mac version 3.2.57 under OS X 10.11.4 El Capitan (Darwin 15.4.0).
There is no way to have it working.
One way is to use a temporary file like:
TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
This works on both
If you really want to just use sed -i
the 'easy' way, the following DOES work on both GNU and BSD/Mac sed
:
sed -i.bak 's/foo/bar/' filename
Note the lack of space and the dot.
Proof:
# GNU sed
% sed --version | head -1
GNU sed version 4.2.1
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
# BSD sed
% sed --version 2>&1 | head -1
sed: illegal option -- -
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
Obviously you could then just delete the .bak
files.
When on OSX, I always install GNU sed version via Homebrew, to avoid problems in scripts, because most scripts were written for GNU sed versions.
brew install gnu-sed --with-default-names
Then your BSD sed will be replaced by GNU sed.
Alternatively, you can install without default-names, but then:
PATH
as instructed after installing gnu-sed
gsed
or sed
depending on your systemSteve Powell's answer is quite correct, consulting the MAN page for sed on OSX and Linux (Ubuntu 12.04) highlights the in-compatibility within 'in-place' sed usage across the two operating systems.
JFYI, there should be no space between the -i and any quotes (which denote an empty file extension) using the Linux version of sed, thus
sed Linux Man Page
#Linux
sed -i""
and
sed OSX Man page
#OSX (notice the space after the '-i' argument)
sed -i ""
I got round this in a script by using an alias'd command and the OS-name output of 'uname' within a bash 'if'. Trying to store OS-dependant command strings in variables was hit and miss when interpreting the quotes. The use of 'shopt -s expand_aliases' is necessary in order to expand/use the aliases defined within your script. shopt's usage is dealt with here.