Is there any alternative to the "sed -i" command in Solaris?
Solution 1
Use ed
. It's available on most platforms and it can edit your files in-place.
Since sed
is based on ed
the syntax for replacing patterns is similar:
ed -s infile <<\IN
,s/old/new/g
w
q
IN
Solution 2
If you cannot install GNU sed, use:
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
This uses redirection to send the output of sed to a temporary file. If sed completes successfully, then this overwrites abc.txt
with the temporary file.
As can be seen from the source code for GNU sed, this is exactly what sed -i
does. So, this is just about as efficient as sed -i
.
If there is a chance that abc.tmp
already exists, then you may want to use mktemp
or a similar utility to generate the unique name for the temporary.
Solution 3
First, you should know that the i\
command you're referring to is for inserting a line of text—not for saving the edited text back to the file. There is no POSIX-specified way to use sed
for that.
What you can do is use ex
, which is specified by POSIX:
printf '%s\n' '%s/find/replace/g' 'x' | ex file.txt
The x
command is for "save and exit." You can also use wq
but x
is shorter.
The %
sign at the start of the substitute command means, "Apply this command to every line in the buffer." You could use 1,$s/find/replace/g
also.
One major difference between ex
and sed
is that sed
is a stream editor. It only operates sequentially, line by line. ex
is far more flexible than that, and in fact you can do interactive text file editing directly in ex
. It is the immediate predecessor to vi
.
Solution 4
If you want the equivalent of sed -i.bak
, it's pretty simple.
Consider this script for GNU sed:
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
We can simply replace the marked line with
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
This moves the existing file to be a backup, and writes a new file.
If we want the equivalent of
sed -i -e "$script" "$dir" # no backup
then it's slightly more complex. We can open the file for reading as standard input, then unlink it, before directing sed's output to replace it:
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
We do this in a sub-shell, so that our original stdin is still available after this. It's possible to switch inputs and switch back without a subshell, but this way seems clearer to me.
Note that we're careful to copy first, rather than creating a new foo
file - this is important if the file is known by more than one name (i.e. has hard links) and you want to be sure that you don't break the links.
Solution 5
Using sed
and no visible temporary file:
You can avoid creating a separate visible "temp file":
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
Explanation
Unix-like systems don't actually remove the file's contents from the disk until it's both unlinked in the filesystem, and not open in any process. So you can do exec 3<
to open the file in the shell for reading on file descriptor 3, rm
the file (which unlinks it from the file system), and then call sed
with file descriptor 3 used as its input.
Note that this is very different from this:
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
The difference is that when you do it in one command, the shell just opens the same file for both reading, and for writing with the option to truncate the file - since it's still the same file, you lose the contents. But if you open it for reading, then rm
it, then open the same pathname for writing, you're actually creating a new file at the same pathname (but at a new inode and disk location, since the original is still open): so the contents are still available.
Then once you're done, you can close the file descriptor you opened previously (that's what the exec 3<&-
special syntax does), which releases the original file so the operating system can delete (mark as unused) its disk space.
Caveats
There's a few things to keep in mind about this solution:.
You only get one "go" through the contents - there's no portable way for a shell to "seek" back in the file descriptor - so once a program reads some of the contents, other programs will only see the remainder of the file. And
sed
will read the entire file.There's a small chance of your original file being lost if your shell/script/sed gets killed before it's done.
Related videos on Youtube
tpsaitwal
Hello I am an excellent programmer, currently working with Deutsche Bank Of India. Placed in Pune and I love to look into and solve questions on Web development and take an interest in developing the same. Look forward to an intense scene. "I would agree with you, but that would make us both wrong." Respect and Loyalty.
Updated on September 18, 2022Comments
-
tpsaitwal over 1 year
I have a requirement in my project to replace some existing text in a file like
foo
with some other text likefooofoo
:abc.txt name foo foo1
So I tried:
sed -i "s/foo/fooofoo/g" abc.txt
However I get this error:
sed: illegal option --
i
I found in the manual that I have to use:
sed -i\ "s/foo/fooofoo/g" abc.txt
However this is not working either.
I found alternatives in
perl
andawk
also but a solution in Solarissed
would be much appreciated.I am using this version of bash:
GNU bash, version 3.2.57(1)-release (sparc-sun-solaris2.10)
-
MusiGenesis over 7 yearsOn Solaris 11 and later, simply use
/usr/gnu/bin/sed
to get -i support.
-
-
tpsaitwal over 7 yearsThanks for help. However Is there any option in solaris by which we can update the existing file without creating a temp file?
-
Jeff Schaller over 7 yearsHate to break it to you, but even sed creates a temporary file. git.savannah.gnu.org/cgit/sed.git/tree/sed/sed.c#n84
-
Toby Speight over 7 yearsYou can do it if you don't care about hard links - see my example. There's still a temporary file, but it's hidden (unnamed). Without a temporary, you'd need to use
ed
, since it reads the whole file into memory. -
Wildcard over 7 years
-
don_crissti over 7 years@Wildcard - I could ask the opposite - why
ex
? To answer your question: since I never useex
I'm not familiar with it. btw, I've seen setups whereed
was present butex
was not (but not the opposite)... the most notable being my laptop :) -
Wildcard over 7 yearsGood answer. :) My answer: Since I use Vim all the time, I am very familiar with
ex
commands. All thevi
commands you can type that start with a colon areex
commands. There are of course a few Vim-specific extensions, but just the core set of commands is incredibly powerful and flexible and is plenty for scripted edits. -
mtraceur over 7 yearsTo the downvoter: While I'm sure just leaving a downvote makes you feel good about yourself, I'd appreciate if you'd contribute more by providing feedback as to what issues you have with this answer, how it can be improved, etc.
-
c4f4t0r over 7 yearsmaybe you can use perl -i
-
mtraceur over 7 years@c4f4t0r: Sorry for the late reply: Yes,
perl -i
is another good option. The question specifically requested a solution compatible with Solaris'sed
, in contrast to solutions withperl
andawk
that they mentioned already finding. Plus, my answer was mainly intended to add something that I thought was useful to know and missing from any of the other answers. -
mid over 4 yearsMy Manjaro system has
ex
and yet noted
.