Im trying to change words in a Unix file using sed but I keep getting an error - bash

I keep getting this error message and don't understand why. How do I fix it. I am using the bash shell on a Unix system.
$ sed -i 's/ he/ she/g' S13a4sed
sed: illegal option -- i

sed command parameter option i is not available in some of the unix environment, for example SunOS Just use like below it will work for you.
$ sed 's/ he/ she/g' S13a4sed
Just test it like below:-
echo " he is a girl" | sed 's/ he/ she/g'
Output
she is a girl

sed's -i option is a feature of GNU's sed. Unfortunately you can't use it on your system. But you can use perl as well:
$ cat S13a4sed
he is a girl
$ perl -pi -e 's/he/she/g' S13a4sed
$ cat S13a4sed
she is a girl
From here: sed -i + what the same option in SOLARIS

Related

How to replace '/' with '/\' using sed in shell scripting

I am trying to replace
prakash/annam/DevOps ---> prakash/\annam/\Devops
I am using this:
sed "s/'[//]''///\\/g"
Unfortunately, it is not giving the required output can anyone please help with this!!!
you can use a separator other than slash:
$ sed 's#/#\\/#g' <<< "a/b/c"
a\/b\/c
$ sed 's#/#/\\#g' <<< "a/b/c"
a/\b/\c
You can use sed with -i flag to place in place changes to the file
*nix
$ cat test
prakash/annam/DevOps
$ sed -i 's/\//\/\\/g' test
$ cat test
prakash/\annam/\DevOps
MacOS
$ cat test
prakash/annam/DevOps
$ sed -i '' 's/\//\/\\/g' test
$ cat test
prakash/\annam/\DevOps
Use
sed -E 's/\//\/\\/g'
e.g.
$ echo "prakash/annam/DevOps" | sed -E 's/\//\/\\/g'
prakash/\annam/\DevOps

Error on sed script - extra characters after command

I've been trying to create a sed script that reads a list of phone numbers and only prints ones that match the following schemes:
+1(212)xxx-xxxx
1(212)xxx-xxxx
I'm an absolute beginner, but I tried to write a sed script that would print this for me using the -n -r flags (the contents of which are as follows):
/\+1\(212\)[0-9]{3}-[0-9]{4}/p
/1\(212\)[0-9]{3}-[0-9]{4}/p
If I run this in sed directly, it works fine (i.e. sed -n -r '/\+1\(212\)[0-9]{3}-[0-9]{4}/p' sample.txt prints matching lines as expected. This does NOT work in the sed script I wrote, instead sed says:
sed: -e expression #1, char 2: extra characters after command
I could not find a good solution, this error seems to have so many causes and none of the answers I found apply easily here.
EDIT: I ran it with sed -n -r script.sed sample.txt
sed can not automatically determine whether you intended a parameter to be a script file or a script string.
To run a sed script from a file, you have to use -f:
$ echo 's/hello/goodbye/g' > demo.sed
$ echo "hello world" | sed -f demo.sed
goodbye world
If you neglect the -f, sed will try to run the filename as a command, and the delete command is not happy to have emo.sed after it:
$ echo "hello world" | sed demo.sed
sed: -e expression #1, char 2: extra characters after command
Of the various unix tools out there, two use BRE as their default regex dialect. Those two tools are sed and grep.
In most operating systems, you can use egrep or grep -E to tell that tool to use ERE as its dialect. A smaller (but still significant) number of sed implementations will accept a -E option to use ERE.
In BRE mode, however, you can still create atoms with brackets. And you do it by escaping parentheses. That's why your initial expression is failing -- the parentheses are NOT special by default in BRE, but you're MAKING THEM SPECIAL by preceding the characters with backslashes.
The other thing to keep in mind is that if you want sed to execute a script from a command line argument, you should use the -e option.
So:
$ cat ph.txt
+1(212)xxx-xxxx
1(212)xxx-xxxx
212-xxx-xxxx
$ grep '^+\{0,1\}1([0-9]\{3\})' ph.txt
+1(212)xxx-xxxx
1(212)xxx-xxxx
$ egrep '^[+]?1\([0-9]{3}\)' ph.txt
+1(212)xxx-xxxx
1(212)xxx-xxxx
$ sed -n -e '/^+\{0,1\}1([0-9]\{3\})/p' ph.txt
+1(212)xxx-xxxx
1(212)xxx-xxxx
$ sed -E -n -e '/^[+]?1\([0-9]{3}\)/p' ph.txt
+1(212)xxx-xxxx
1(212)xxx-xxxx
Depending on your OS, you may be able to get a full list of how this works from man re_format.

sed: urecognized option -- i

I'm using Window 7.
sed -V
gives me
GNU sed version 3.02
I have a text file with:
foo bar
In command line if I write:
sed s/foo/tofu/ test.txt
I get printed on stdout;
tofu bar
However, I want to edit this file inplace, so using the -i option:
sed -i s/foo/tofu/ test.txt
gives me sed: invalid option -- i
What am I missing?
While I can't guarantee this will work because I'm not running it on Windows 7 but have you considered using redirection and then swapping?
Meaning something like this:
sed s/foo/tofu/ test.txt > tmp.txt && mv tmp.txt test.txt
While this is a very dirty way of doing things I think it might work. You can also try doing
sed s/foo/tofu/ test.txt > test.txt
but I feel that might lead to some errors because you're reading and writing on the same file.
It's the sed version. Try the one found here:
http://unxutils.sourceforge.net/UnxUpdates.zip

In-place edits with sed on OS X

I'd like edit a file with sed on OS X. I'm using the following command:
sed 's/oldword/newword/' file.txt
The output is sent to the terminal. file.txt is not modified. The changes are saved to file2.txt with this command:
sed 's/oldword/newword/' file1.txt > file2.txt
However I don't want another file. I just want to edit file1.txt. How can I do this?
I've tried the -i flag. This results in the following error:
sed: 1: "file1.txt": invalid command code f
You can use the -i flag correctly by providing it with a suffix to add to the backed-up file. Extending your example:
sed -i.bu 's/oldword/newword/' file1.txt
Will give you two files: one with the name file1.txt that contains the substitution, and one with the name file1.txt.bu that has the original content.
Mildly dangerous
If you want to destructively overwrite the original file, use something like:
sed -i '' 's/oldword/newword/' file1.txt
^ note the space
Because of the way the line gets parsed, a space is required between the option flag and its argument because the argument is zero-length.
Other than possibly trashing your original, I’m not aware of any further dangers of tricking sed this way. It should be noted, however, that if this invocation of sed is part of a script, The Unix Way™ would (IMHO) be to use sed non-destructively, test that it exited cleanly, and only then remove the extraneous file.
I've similar problem with MacOS
sed -i '' 's/oldword/newword/' file1.txt
doesn't works, but
sed -i"any_symbol" 's/oldword/newword/' file1.txt
works well.
The -i flag probably doesn't work for you, because you followed an example for GNU sed while macOS uses BSD sed and they have a slightly different syntax.
All the other answers tell you how to correct the syntax to work with BSD sed. The alternative is to install GNU sed on your macOS with:
brew install gsed
and then use it instead of the sed version shipped with macOS (note the g prefix), e.g:
gsed -i 's/oldword/newword/' file1.txt
If you want GNU sed commands to be always portable to your macOS, you could prepend "gnubin" directory to your path, by adding something like this to your .bashrc/.zshrc file (run brew info gsed to see what exactly you need to do):
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
and from then on the GNU sed becomes your default sed and you can simply run:
sed -i 's/oldword/newword/' file1.txt
sed -i -- "s/https/http/g" file.txt
You can use -i'' (--in-place) for sed as already suggested. See: The -i in-place argument, however note that -i option is non-standard FreeBSD extensions and may not be available on other operating systems. Secondly sed is a Stream EDitor, not a file editor.
Alternative way is to use built-in substitution in Vim Ex mode, like:
$ ex +%s/foo/bar/g -scwq file.txt
and for multiple-files:
$ ex +'bufdo!%s/foo/bar/g' -scxa *.*
To edit all files recursively you can use **/*.* if shell supports that (enable by shopt -s globstar).
Another way is to use gawk and its new "inplace" extension such as:
$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1
This creates backup files. E.g. sed -i -e 's/hello/hello world/' testfile for me, creates a backup file, testfile-e, in the same dir.
You can use:
sed -i -e 's/<string-to-find>/<string-to-replace>/' <your-file-path>
Example:
sed -i -e 's/Hello/Bye/' file.txt
This works flawless in Mac.
If you need to substitute more than one different words:
sed -i '' -e 's/_tools/tools/' -e 's/_static/static/' test.txt

Text substitution (reading from file and saving to the same file) on linux with sed

I want to read the file "teste", make some "find&replace" and overwrite "teste" with the results. The closer i got till now is:
$cat teste
I have to find something
This is hard to find...
Find it wright now!
$sed -n 's/find/replace/w teste1' teste
$cat teste1
I have to replace something
This is hard to replace...
If I try to save to the same file like this:
$sed -n 's/find/replace/w teste' teste
or:
$sed -n 's/find/replace/' teste > teste
The result will be a blank file...
I know I am missing something very stupid but any help will be welcome.
UPDATE: Based on the tips given by the folks and this link: http://idolinux.blogspot.com/2008/08/sed-in-place-edit.html here's my updated code:
sed -i -e 's/find/replace/g' teste
On Linux, sed -i is the way to go. sed isn't actually designed for in-place editing, though; historically, it's a filter, a program which edits a stream of data in a pipeline, and for this usage you would need to write to a temporary file and then rename it.
The reason you get an empty file is that the shell opens (and truncates) the file before running the command.
You want: sed -i 's/foo/bar/g' file
You want to use "sed -i". This updates in place.
In-place editing with perl
perl -pi -w -e 's/foo/bar/g;' file.txt
or
perl -pi -w -e 's/foo/bar/g;' files*
for many files
The ed solution is:
ed teste <<END
1,$s/find/replace/g
w
q
END
Or without the heredoc
printf "%s\n" '1,$s/find/replace/g' w q | ed teste
Actually, if you use -i flag, sed will copy the original line you edit.
So this might be a better way:
sed -i -e 's/old/new/g' -e '/new/d' file
There is a useful sponge command.
sponge soaks up all its input before opening the output file.
$cat test.txt | sed 's/find/replace/w' | sponge test.txt
Nothing worked for me on MacOS, but after some research I found this answer.
So the following works on MacOS:
sed -i '' -e 's/find/replace/g' teste
However, on Linux distro's (in my pipelines) the following worked and the above command throwed errors:
sed -i -e 's/find/replace/g' teste

Resources