I am trying to run sed from CMake. The problem is that CMake really messes up the expressions passed to sed. Here's a snippet from the CMakeLists.txt file:
${SED_TOOL} -e "'1 s#.*#\#include \"config.hpp\"\\nnamespace LANG_NAMESPACE {\\nnamespace lexyacc {\\n\\n&#'" -e "'\$ s#.*#&\\n}}\\n#'"
And here's what CMake turns it into:
/bin/sed -e '1\ s#.*##include\ "config.hpp"\nnamespace\ LANG_NAMESPACE\ {\nnamespace\ lexyacc\ {\n\n&#' -e '$\ s#.*#&\n}}\n#'
How should I fix this? And is there any good reference on how CMake's quoting works?
EDIT: here's an example:
http://pastebin.com/G9NRfrp7
http://pastebin.com/y9776Lt9
Why do you think you need the outer-most surrounding dbl-quote chars. Cmake is almost certainly passing the sed cmd to a shell, which then executes it. Putting the sed strings in dbl-quotes means some extra evaluation will be performed. Eliminate dbl-quotes, unless you need to have a variable evaluated, and then use something like
sed -e 's/xxx/yyy/;s/'"${var1}/${var2}"'/;s/www/zzz/'
I hope this helps.
Related
I have this regex that works fine enough for my purposes for identifying emails in CSVs within a directory using grep on Mac OS X:
grep --no-filename -E -o "\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" *
I've tried to get this working with sed so that I can replace the emails with foo#bar.baz:
sed -E -i '' -- 's/\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b/foo#bar.baz/g' *
However, I can't seem to get it to work. Admittedly, sed and regex are not my strong points. Any ideas?
The sed in OSX is broken. Replace it with GNU sed using Homebrew that will be used as a replacement for the one bundled in OSX. Use this command for installation
sudo brew install gnu-sed
and use this for substitution
sed -E -i 's/\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b/foo#bar.baz/g' *
Reference
You seem to assume that grep and sed support the same regex dialect, but that is not necessarily, or even usually, the case.
If you want a portable solution, you could easily use Perl for this, which however supports yet another regex dialect...
perl -i -p -e 's/\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b/foo#bar.baz/g' *
For a bit of an overview of regex dialects, see https://stackoverflow.com/a/11857890/874188
Your regex kind of sucks, but I understand that is sort of beside the point here.
I am trying to compile a large project that I downloaded from Internet and I have a custom script that runs configure, make and make install. The problem is that I want to pass some compatibility flags but the project uses libtool which doesn't recognize LDFLAGS and I have to find another way to pass my compatibility flags. So in my script after running configure I have code that looks like this:
COMPATFLAG="-gcc-name=/usr/local/gcc-4.2.1/bin/gcc"
sed -i "s/CC -shared/CC -shared ${COMPATFLAG}/g" libtool
${COMPATFLAG} may get different values depending on what platform is being compiled for so I cannot put it in clear text in the sed statement. The problem is that it doesn't work - I get an empty space instead of the value of ${COMPATFLAG}. If I instead write sed -i "s/CC -shared/CC -shared TEST/g" libtool it adds the string "TEST" to the file. If I use single quotes I get the ${COMPATFLAG} string and not the variable's value. If I try to export ${COMPATFLAG} it still doesn't work. I don't know why it goes wrong. Any idea?
Since COMPATFLAG does have forward slashes you should use a different regex delimiter in sed:
sed -i "s#CC -shared#& ${COMPATFLAG}#g" libtool
Also I have used # here in order to avoid repetition of matched string in replacement pattern.
Thanks to #JonathanLeffler for this tip, you can even use a control character as regex delimiter:
sed -i "s^GCC -shared^G& ${COMPATFLAG}^Gg" libtool
Type ^G as ctrl-V-G in shell
You can use pipe | instead of / with a double quote. That works for the global variables that include /.
sed -e "s|CC -shared|CC -shared ${COMPATFLAG}|g" libtool
I've got a file structure that looks like:
A/
2098765.1ext
2098765.2ext
2098765.3ext
2098765.4ext
12345.1ext
12345.2ext
12345.3ext
12345.4ext
B/
2056789.1ext
2056789.2ext
2056789.3ext
2056789.4ext
54321.1ext
54321.2ext
54321.3ext
54321.4ext
I need to rename all the files that begin with 20 to start with 10; i.e., I need to rename B/2022222.1ext to B/1022222.1ext
I've seen many of the other questions regarding renaming multiple files, but couldn't seem to make it work for my case. Just to see if I can figure out what I'm doing before I actually try to do the copy/renaming I've done:
for file in "*/20?????.*"; do
echo "{$file/20/10}";
done
but all I get is
{*/20?????.*/20/10}
Can someone show me how to do this?
You just have a little bit of incorrect syntax is all:
for file in */20?????.*; do mv $file ${file/20/10}; done
Remove quotes from the argument to in. Otherwise, the filename expansion does not occur.
The $ in the substitution should go before the bracket
Here is a solution which use the find command:
find . -name '20*' | while read oldname; do echo mv "$oldname" "${oldname/20/10}"; done
This command does not actually do your bidding, it only prints out what should be done. Review the output and if you are happy, remove the echo command and run it for real.
Just wanna add to Explosion Pill's answer.
On OS X though, you must say
mv "${file}" "${file_expression}"
Or the mv command does not recognize it.
Brace expansions like :
{*/20?????.*/20/10}
can't be surrounded by quotes.
Instead, try doing (with Perl rename) :
rename 's/^10/^20/' */*.ext
You can do this using the Perl tool rename from the shell prompt. (There are other tools with the same name which may or may not be able to do this, so be careful.)
If you want to do a dry run to make sure you don't clobber any files, add the -n switch to the command.
note
If you run the following command (linux)
$ file $(readlink -f $(type -p rename))
and you have a result like
.../rename: Perl script, ASCII text executable
then this seems to be the right tool =)
This seems to be the default rename command on Ubuntu.
To make it the default on Debian and derivative like Ubuntu :
sudo update-alternatives --set rename /path/to/rename
The glob behavior of * is suppressed in double quotes. Try:
for file in */20?????.*; do
echo "${file/20/10}";
done
I need to write multiple sed script files. I can't seem to find a way to enable extended regex from within the script. Is this possible? It isn't possible for me to use option flags because the scripts need to run on an external environment which isn't under my control.
You can try specifying the flag in the script shebang, say:
#!/bin/sed -rf
# script goes here
And then tell the admin to run the script as is (chmod a+x it first, then ./script.sed) so the shebang line is used for finding the right interpreter.
You may need to substitute /bin/sed with the right path for your environment. Unfortunately you probably won't be able to use /usr/bin/env sed -r for this (the extra -r is a problem).
I think the answer to your question is "no", but, if this is GNU sed, then you probably don't really need extended regular expressions, because GNU sed's implementation of basic regular expressions actually supports the features of EREs that true POSIX BREs don't. Admittedly, the result is incredibly, painfully backslash-heavy — ERE's s/(a|b+|cd?)/e/g becomes BRE's s/\(a\|b\+\|cd\?\)/e/g — but it works.
I'm working on some old code and I found that I used to use
sed -E 's/findText/replaceWith/g' #findText would contain a regex
but I now try
sed -e 's/findText/replaceWith/g'
It seems to do the same thing, or does it?
I kinda remember there being a reason I done it but I can't remember and doing "man sed" doesn't help as they don't have anything about -E only -e that doesn't make much sense ether.
-e, --expression=script
Append the editing commands in script to the end of
the editing command script. script may contain more
than one newline separated command.
I thought -e meant it would match with a regex...
GNU sed version 4.2.1
From source code, -E is an undocumented option for compatibility with BSD sed.
/* Undocumented, for compatibility with BSD sed. */
case 'E':
case 'r':
if (extended_regexp_flags)
usage(4);
extended_regexp_flags = REG_EXTENDED;
break;
And from manual, -E in BSD sed is used to support extended regular expressions.
From sed's documentation:
-E
-r
--regexp-extended
Use extended regular expressions rather than basic regular expressions. Extended regexps are those that egrep accepts; they can be clearer because they usually have fewer backslashes. Historically this was a GNU extension, but the -E extension has since been added to the POSIX standard (http://austingroupbugs.net/view.php?id=528), so use -E for portability. GNU sed has accepted -E as an undocumented option for years, and *BSD seds have accepted -E for years as well, but scripts that use -E might not port to other older systems. See Extended regular expressions.
Therefore it seems that -E should be the preferred way to declare that you are going to use (E)xtended regular expressions, rather than -r.
Instead, -e just specifies that what follows is the script that you want to execute with sed (something like 's/bla/abl/g').
Always from the documentation:
Without -e or -f options, sed uses the first non-option parameter as the script, and the following non-option parameters as input files.