why did I get error in sed command? - shell

$ ls | sed -n "/c/{/s/r/ssss/;p}"
When running this line in terminal, I got:
sed: -e expression #1, char 0: unmatched `{'
What's wrong?

I think there's one too many / characters in there.
You probably need:
ls | sed -n "/c/{ s/r/ssss/;p;}"
This looks for lines from ls containing a c, and replaces the first r with ssss and prints the result.
It works with the Mac (BSD) version of sed and the GNU version too. The GNU version is OK without the semicolon after the p but the Mac version is not.
However, there could be other ways to interpret what you're trying to do, and that might lead to a different command line. If you're trying to find a line containing a c and an s and replace the whole line with ssss (and maybe some other characters — it isn't clear what you've aiming for), then you'd have to do more work, in both GNU and Mac/BSD versions of sed.

Related

How to insert characters in the middle of every two consecutive repeating characters?

I have a file like this:
user$ cat -t file
0.1^I^I^I0.2
I wish to edit the file so that every time two consecutive tabs appear, the characters "NA" are inserted in the middle of the two tabs. The number of consecutive tab characters that could appear is arbitrary (in this example there are three tabs in succession but it could be two or more than three).
I've tried doing this with sed (BSD sed):
user$ cat -t <(sed $'s/\t\t/\tNA\t/g' file)
But this only inserts the desired characters in the middle of the first two consecutive tabs yielding this output:
0.1^INA^I^I0.2
I also need the characters to be inserted in the middle of the second pair of consecutive tabs in order to get this output:
0.1^INA^INA^I0.2
Would prefer to use sed for this, but other tools such as awk or perl could be used.
The problem is that sed doesn't do overlapping matches. We need to repeat the substitution until all matches have been made. Thus, try:
$ cat -t <(sed ':a; s/\t\t/\tNA\t/g; ta' file)
0.1^INA^INA^I0.2
Consider \t\t\t. The substitution command matches the first \t\t and replaces it with \tNA\t. The problem is that, with the g option, the next substitution can only start after those first two tabs. Overlapping substitutions are not supported. That is why we need to add the label and branching commands as above.
How it works
:a
This creates a label a.
s/\t\t/\tNA\t/g
This does the substitution you want.
ta
If the preceding substitution command successfully made a substitution, this tells sed to jump back to label a. Consequently, the substitution command will be repeated as many times as necessary.
BSD Version
With thanks to mikekatz45, the BSD version is:
cat -t <(sed -e :a -e $'s/\t\t/\tNA\t/g' -e ta file)
Note that, while the $'...' construct is not POSIX, it will work under bash, ksh, and zsh.
Perl version using a 0-width lookahead to make the matches not overlap:
$ echo -e "0.1\t\t\t0.2" | perl -pe 's/\t(?=\t)/\tNA/g' | cat -t
0.1^INA^INA^I0.2
Or for modifying a file in-place:
$ perl -pi -e 's/\t(?=\t)/\tNA/g' blah.txt

to insert line breaks in a file whenever a comma is encountered-Shell script

I need to write a shell script to re-format a file by inserting line breaks. The condition is that a line break should be inserted when we encounter comma in the file.
For example, if the file delimiter.txt contains:
this, is a file, that should, be added, with a, line break, when we find, a comma.
The output should be:
this
is a file
that should
be added
with a
line break
when we find a
a comma.
Can this be done grep or awk?
Using GNU sed:
sed 's/, /\n/g' your.file
Output:
this
is a file
that should
be added
with a
line break
when we find a
a comma.
Note: the syntax above will work only on system that have the \n as line delimiter as Linux and the most UNIXes.
If you need a portal solution in a a script then use the following expression that uses a literal new line instead of \n:
sed 's/,[[:space:]]/\
/g' your.file
Thanks #EdMorten for this advice.
This is what tr is for
$ tr ',' '\n' <<< 'this, is a file, that should, be added, with a, line break, when we find, a comma.'
this
is a file
that should
be added
with a
line break
when we find
a comma.
Or if you must use awk:
awk '{gsub(", ", "\n", $0)}1' delimiter.txt
Solution using awk:
awk 1 RS=", " file
this
is a file
that should
be added
with a
line break
when we find
a comma.
Here's the solution using perl:
perl -pe 's#,#\n#g'
Here's a sample of it working properly on OpenBSD or OS X:
% echo 'a,b,c,d,e' | perl -pe 's#,#\n#g'
a
b
c
d
e
%
E.g., unlike the sed solutions earlier, this perl works everywhere, because the same search/replace snippet wouldn't work with the BSD sed on OpenBSD or OS X:
% echo 'a,b,c,d,e' | sed -E 's#,#\n#g'
anbncndne
%

SED command error on MACOS X

I am trying to run this command on MacOSX terminal , which was initially intended to run on Linux
sed '1 i VISPATH=/mnt/local/gdrive/public/3DVis' init.txt >> ~/.bash_profile
but it gives me the error:
command i expects \ followed by text.
is there any way I could modify the above command to work on MacOSX terminal
Shelter is right but there's another way to do it. You can use the bash $'...' quoting to interpret the escapes before passing the string to sed.
So:
sed -iold '1i\'$'\n''text to prepend'$'\n' file.txt
^^^^^^^^ ^
/ |\|||/ \ |__ No need to reopen
| | \|/ | string to sed
Tells sed to | | | |
escape the next _/ | | +-----------------------------+
char | +-------------+ |
| | |
Close string The special bash Reopen string to
to sed newline char to send to sed
send to sed
This answer on unix.stackexchange.com led me to this solution.
Had the same problem and solved it with brew:
brew install gnu-sed
gsed YOUR_USUAL_SED_COMMAND
If you want to use the sed command, then you can set an alias:
alias sed=gsed
The OSX seds are based on older versions, you need to be much more literal in your directions to sed, AND you're lucky, in this case, sed is telling you exactly what to do. Untested as I don't have OSX, but try
sed '1 i\
VISPATH=/mnt/local/gdrive/public/3DVis
' init.txt >> ~/.bash_profile
Input via the i cmd is terminated by a blank line. Other sed instructions can follow after that. Note, NO chars after the \ char!
Also, #StephenNiedzielski is right. Use the single quote chars to wrap your sed statements. (if you need variable expansion inside your sed and can escape other uses of $, then you can also use dbl-quotes, but it's not recommended as a normal practices.
edit
As I understand now that you're doing this from the command-line, and not in a script or other editor, I have tested the above, and.... all I can say is that famous line from tech support ... "It works for me". If you're getting an error message
sed: -e expression #1, char 8: extra characters after command
then you almost certainly have added some character after the \. I just tested that, and I got the above error message. (I'm using a linux version of sed, so the error messages are exactly the same). You should edit your question to include an exact cut-paste of your command line and the new error message. Using curly-single-quotes will not work.
IHTH
Here's how I worked it out on OS X. In my case, I needed to prepend text to a file. Apparently, modern sed works like this:
sed -i '1i text to prepend' file.txt
But on OS X I had to do the following:
sed -i '' '1i\
text to prepend
' file.txt
It looks like you copied rich text. The single quotes should be straight not curly:
sed '1 i VISPATH=/mnt/local/gdrive/public/3DVis'

Replace comma with newline in sed on MacOS?

I have a file of strings that are comma separated. I'm trying to replace the commas with a new line. I've tried:
sed 's/,/\n/g' file
but it is not working. What am I missing?
Use tr instead:
tr , '\n' < file
Use an ANSI-C quoted string $'string'
You need a backslash-escaped literal newline to get to sed.
In bash at least, $'' strings will replace \n with a real newline, but then you have to double the backslash that sed will see to escape the newline, e.g.
echo "a,b" | sed -e $'s/,/\\\n/g'
Note this will not work on all shells, but will work on the most common ones.
sed 's/,/\
/g'
works on Mac OS X.
If your sed usage tends to be entirely substitution expressions (as mine tends to be), you can also use perl -pe instead
$ echo 'foo,bar,baz' | perl -pe 's/,/,\n/g'
foo,
bar,
baz
MacOS is different, there is two way to solve this problem with sed in mac
first ,use \'$'\n'' replace \n, it can work in MacOS:
sed 's/,/\'$'\n''/g' file
the second, just use an empty line:
sed 's/,/\
/g' file
Ps. Pay attention the range separated by '
the third, use gnu-sed replace the mac-sed
Apparently \r is the key!
$ sed 's/, /\r/g' file3.txt > file4.txt
Transformed this:
ABFS, AIRM, AMED, BOSC, CALI, ECPG, FRGI, GERN, GTIV, HSON, IQNT, JRCC, LTRE,
MACK, MIDD, NKTR, NPSP, PME, PTIX, REFR, RSOL, UBNT, UPI, YONG, ZEUS
To this:
ABFS
AIRM
AMED
BOSC
CALI
ECPG
FRGI
GERN
GTIV
HSON
IQNT
JRCC
LTRE
MACK
MIDD
NKTR
NPSP
PME
PTIX
REFR
RSOL
UBNT
UPI
YONG
ZEUS
This works on MacOS Mountain Lion (10.8), Solaris 10 (SunOS 5.10) and RHE Linux (Red Hat Enterprise Linux Server release 5.3, Tikanga)...
$ sed 's/{pattern}/\^J/g' foo.txt > foo2.txt
... where the ^J is done by doing ctrl+v+j. Do mind the \ before the ^J.
PS, I know the sed in RHEL is GNU, the MacOS sed is FreeBSD based, and although I'm not sure about the Solaris sed, I believe this will work pretty much with any sed. YMMV tho'...
To make it complete, this also works:
echo "a,b" | sed "s/,/\\$(echo -e '\n\r')/"
Though I am late to this post, just updating my findings. This answer is only for Mac OS X.
$ sed 's/new/
> /g' m1.json > m2.json
sed: 1: "s/new/
/g": unescaped newline inside substitute pattern
In the above command I tried with Shift+Enter to add new line which didn't work. So this time I tried with "escaping" the "unescaped newline" as told by the error.
$ sed 's/new/\
> /g' m1.json > m2.json
Worked! (in Mac OS X 10.9.3)
$ echo $PATH | sed -e $'s/:/\\\n/g'
/usr/local/sbin
/Library/Oracle/instantclient_11_2/sdk
/usr/local/bin
...
Works for me on Mojave
Just to clearify: man-page of sed on OSX (10.8; Darwin Kernel Version 12.4.0) says:
[...]
Sed Regular Expressions
The regular expressions used in sed, by default, are basic regular expressions (BREs, see re_format(7) for more information), but extended
(modern) regular expressions can be used instead if the -E flag is given. In addition, sed has the following two additions to regular
expressions:
1. In a context address, any character other than a backslash (``\'') or newline character may be used to delimit the regular expression.
Also, putting a backslash character before the delimiting character causes the character to be treated literally. For example, in the
context address \xabc\xdefx, the RE delimiter is an ``x'' and the second ``x'' stands for itself, so that the regular expression is
``abcxdef''.
2. The escape sequence \n matches a newline character embedded in the pattern space. You cannot, however, use a literal newline charac-
ter in an address or in the substitute command.
[...]
so I guess one have to use tr - as mentioned above - or the nifty
sed "s/,/^M
/g"
note: you have to type <ctrl>-v,<return> to get '^M' in vi editor
The sed on macOS Mojave was released in 2005, so one solution is to install the gnu-sed,
brew install gnu-sed
then use gsed will do as you wish,
gsed 's/,/\n/g' file
If you prefer sed, just sudo sh -c 'echo /usr/local/opt/gnu-sed/libexec/gnubin > /etc/paths.d/brew', which is suggested by brew info gnu-sed. Restart your term, then your sed in command line is gsed.
FWIW, the following line works in windows and replaces semicolons in my path variables with a newline. I'm using the tools installed under my git bin directory.
echo %path% | sed -e $'s/;/\\n/g' | less
I have found another command that is working also.
find your_filename.txt -type f -exec sed -i 's/,/\n/g' {} \;

need help porting a sed command from debian to OSX

This is one for you sed gurus out there. I really don't know enough about sed to take this apart completely. It was written on some standard Linux distro and I need it to run on OSX.
COMPILE_FILES=$(sed -nr '/<script type="text\/javascript"/ { s%^.*src="\{\$baseUrl\}/([^"]+)".*$%\1%p }' templates/common/minifiedScripts.tpl)
The first thing is that the r flag doesn't exist on the OSX version of sed. I thought the equivalent is -E, so changed it. But then I get:
sed: 1: "/<script type="text\/ja ...": bad flag in substitute command: '}'
Thanks!
OS X sed doesn't like multiple commands run together using semicolons or grouped in curly braces (which aren't necessary in the command you have). Try this:
COMPILE_FILES=$(sed -n -E '/<script type="text\/javascript"/ s%^.*src="\{\$baseUrl\}/([^"]+)".*$%\1%p' templates/common/minifiedScripts.tpl)
If you have a sed script that consists of multiple commands, you'll have to break them up using -e:
sed -n -E -e '/match/ {' -e 's/foo/bar/' -e 's/baz/qux/' -e 'p' -e '}'
-r uses the extended regular expression set, and you are using one not supported by the OSX version. Try MacPorts or Fink -- they have ports of gnu sed. OR you can just download and compile source directly.

Resources