need help porting a sed command from debian to OSX - macos

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.

Related

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.

why did I get error in sed command?

$ 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.

How to use flag with 'sed' on mac?

I dont find the way to use flag with sed and matching pattern.
I'm trying to us the i flag. But I don't understand how it works.
$ sed -i '' -n '/xxx.xxx#xxx.fr/i d' res.txt
sed: 1: "/xxx.xxx#xxx.fr/i d": command i expects \ followed by text
So I want to match xxx.xxx#xxx.fr And XXX.XXX#XXX.FR
The -i '' is only for --in-file (without cache) the d is for delete.
So how can I use flag and eventually multiple of them ? In the documentation I've found it was that way but it seems not to work at all.
I would use Perl - its regexes and options are far more orthogonal and consistent than all the sed versions across platforms:
perl -i -ne '/XXX.XXX.fr/i || print' res.txt
-i means "in-place" editing
-n means execute a loop around input lines like awk or sed
-e means execute following script

OR matches with BSD sed

I'm trying to filter out the lines in a file that match the regular expression:
DROP (CONSTRAINT|INDEX)
With gnu sed, this works:
gsed -e '/DROP \(CONSTRAINT\|INDEX\)/d' < myfile.sql
However, that same command doesn't work with BSD sed (specifically, the version of sed that ships with Mac OS X 10.8.3). How would I do this with BSD sed?
sed
sed '/DROP/ {/INDEX/d; /CONSTRAINT/d}' file
Not sure about alteration, but you can use a couple of lines in BSD Sed (I, too, am on Mac OS X 10.8.3, so can vouch that this command will work on your platform):
sed '/DROP \(INDEX\)/d;/DROP \(CONSTRAINT\)/d'
To test, I created a plain text file:
DROP INDEX a;
DROP CONSTRAINT b;
CREATE TABLE foo;
Perhaps grep would be a better tool for this job:
grep -v -E 'DROP (CONSTRAINT|INDEX|SEQUENCE|TABLE|EXTENSION|DEFAULT)' file.txt
will print all lines that do not match. I'm not sure that the OSX version of grep supports grep -E, though - it might be called egrep instead. Either one of those works on Linux.

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' {} \;

Resources