Escaping Regex in SED - regex

I need to use Sed to do a search and replace. I'm replacing /**# for define('WP_POST_REVISIONS', 3);\n\n/**#.
But I can't figure out the proper escaping. Even after escaping the (obviously needed) single quotes, I still get a bash: syntax error near unexpected token ')'
What is the proper escaping in this case?

try to replace your:
find /start/path -name *.html -exec sed -ie 's|/**#|define(\'WP_POST_REVISIONS\', 3);|g' '{}' \;
with:
find /start/path -name '*.html' -print0 \
| xargs -0 -n 1 sed -ie 's|/\*\*#|define('\''WP_POST_REVISIONS'\'', 3);\n/\*\*#|g'
and tell us what it gives you
(I tried to guess you were looking for the actual string "/**#" in your file(s) ... please give us examples of what you are really looking for, if it isn't that actual string)

It is not sed escaping, but bash escaping.
Escaping does not work within single-quotes (')
You can use double-quotes ("), if you have no special characters like "$\ in the parameter (or escape them there if necessary):
find /start/path -name *.html -exec sed -ie "s/abc/define('WP_POST_REVISIONS', 3);/g" '{}' \;
Or quote using $', which supports escaping:
find /start/path -name *.html -exec sed -ie $'s/abc/define(\'WP_POST_REVISIONS\', 3);/g' '{}' \;

Related

Using find/sed to replace strings in text files- works only on some of the matches

I want to replace
{not STRING }
with
(not STRING )
I ran
find . -maxdepth 1 -type f -exec sed -i -E 's/{not\s([^\s}]+)\s}/(not \1 )/g' {} ;
It worked on some of the matches. When I run grep with the same pattern it shows more files that still have STRING. Ran find/sed again, same result.
You need to escape curly braces ({}), as they are regex meta-characters. Also \s is not POSIX sed, I would use the more portable [[:space:]].
Your code did not work on the example text for me (GNU/Linux). This does:
sed -E 's/\{not[[:space:]]+([^[:space:]}]+)[[:space:]]+\}/(not \1 )/g'
I also allowed for variable length whitespace directly after not and directly before } (using [[:space:]]+). You may or may not want that.
Also:
On MacOS sed I believe you need to supply a suffix argument to -i.
The trailing ; for find -exec must be quoted (\;) to avoid interpretation by the shell.
So the command would be:
find . -maxdepth 1 -type f -exec \
sed -E -i .TMP 's/\{not[[:space:]]+([^[:space:]}]+)[[:space:]]+\}/(not \1 )/g' {} \;
If .TMP conflicts with an existing file, choose a different suffix.

Perl regex is not matching

I'm trying to pipe the output of a find command to a perl one-liner to replace a line that ends with ?> with RedefineForDocker::standardizeXmlmc() but for some reason the value isn't being replaced. I've checked the output of the find command and it is performing as expected, and I've double checked my regex and it should match.
find . -name *.php -exec ggrep -Ezl 'class XmlMethodCall.*([?]>)$' {} \; \
| xargs perl -ewpn -i.bak2 \
"s/[?]>\s*?$/RedefineForDocker::standardizeXmlmc()\n/gm"
I get no warnings and no indication that it isn't working, the backups are created, but the file remains unchanged. The list of matched files run from the find command is below.
./swsupport/clisupp/trending/services/data.helpers.php
./swsupport/clisupp/_bpmui/arch/service/data.helpers.php
./swsupport/clisupp/_bpmui/itsm/service/data.helpers.php
./swsupport/clisupp/_bpmui/itsm_default/service/data.helpers.php
./webclient_code/php/session.php
./webclient_code/service/storedquery/helpers.php
./php/_phpinclude/itsm/xmlmc/xmlmc.php
./php/_phpinclude/itsmf/xmlmc/xmlmc.php
./php/_phpinclude/itsm_default/xmlmc/xmlmc.php
Here is an example of one of the files it should match
https://regex101.com/r/BUoCif/1
Run your perl command as this:
perl -i.bak2 -wpe 's/\?>\h*$/RedefineForDocker::standardizeXmlmc()\n/gm'
Order of command line option is important here.
Full pipeline should be like this:
find . -name '*.php' -exec ggrep -PZzl '(?ms)class XmlMethodCall.*\?>\h*$' {} + |
xargs -0 perl -i.bak2 -wpe 's/\?>\h*$/RedefineForDocker::standardizeXmlmc()\n/gm'
Note use -Z option in grep and -0 option in xargs to address issues with filenames with whitespaces etc.

How to grep for "string\tstring"?

I need to search a large group of data files. I want to find files that contain the string "foo\tbar\tboo". I have tried this ...
$ find . -name "foo*dat" -exec grep foo {} \; | less
"miscinfo_foo" => [
"foo\tbar\tnot_foo"
"miscinfo_foo",
"miscinfo_foo" => [
"foo\tbar\tyes_foo"
"miscinfo_foo",
But if I do ...
$ find . -name "foo*dat" -exec grep -E "foo\tbar" {} \;
... I get no output. I have tried egrep too. I have tried escaping the \t with \\t but still get no output.
What am I doing wrong?
Thanks
Try
find . -name "foo*dat" -exec grep -E 'foo\\tbar' {} \;
^ ^ ^
in single quotes rather than double, and with an extra backslash. The '' prevent bash from processing backslashes, so that grep will actually see foo\\tbar. Based on your output, I think you are looking for the literal text backslash-tee, not an ASCII character 9, so double the backslash to have grep match it as literal text.
There are two effects at play here:
grep understands that \t means a tab character.
The shell will expand \\ to \ within a double-quoted string.
You want the slash to be escaped, so you need to pass \\t to grep within single quotes:
grep 'foo\\tbar'

Bash script find/sed not working

I have the following line in my bash script:
find . -name "*.html" -print |
xargs sed -i 's/http\:\/\/version2\.staging\.myname\.com//g'
and it's giving me the following error:
sed: 1: "./instant/index. ...": invalid command code .
What I'm trying to do is replace any occurrence of http://version2.staging.myname.com with /. How do you do it?
Usually I use something like:
find . -name "*.html" -exec sed -i 's|http://version2\.staging\.myname\.com/|/|g' '{}' ';'
To test this out, you can first insert an echo statement
find . -name "*.html" -exec echo sed -i 's|http://version2\.staging\.myname\.com/|/|g' '{}' ';'
... that will tell you if the output will be what you expect. I always recommend doing a dry-run with echo first before any mass update. Also you can use | as an alternate regex delimiter to avoid using as many `/' in the paths.
For OSX try this:
find . -name "*.html" -exec sed -i.bak 's#http://version2\.staging\.myname\.com##g' '{}' \; -print
I think you may be using a Mac (and now I see a comment that you are on an iMac). On Mac OS X, the sed -i option requires an argument. That makes sense of your error message. The sed command is interpreting your s/...//g command as the suffix to use for the back up file; it is then trying to interpret the first file name as the sed script, and fortunately, that is not working.
Additionally, you can avoid most of the escaping issues by using some character other than / as the delimiter for s///. Also, it is generally better (especially on Macs where file paths often end up with spaces in them) to avoid xargs and use -exec in find, along with the + option to do what xargs does — namely group many file names into one command invocation.
This leads to:
find . -name "*.html" -type f \
-exec sed -i .bak -e 's%http://version2.staging.myname.com%%g' {} +
(NB: strictly, that will map http://version2-staging*myname#com to / too; if you're really worried about that, by all means escape the dots in the URL.)
If you want to get rid of the .bak files afterwards:
find . -name '*.bak' -type f -exec rm -f {} +

Recursively replace django template tag with sed

I renamed something in my django application, and I want to recursively search and replace the tag in all of the templates. I tried to do this using find and sed like so.
find . -name *.html -exec sed -i 's/\{\{\s*oldtag\s*\}\}/{{ newtag }}/g' {} \;
I get this error.
sed: -e expression #1, char 44: Invalid preceding regular expression
Ok, so I tried a whole bunch of different things to try to make it work. I tried unescaping and double-escaping the curly braces. I tried using [ \t] instead of \s. Nothing seems to work. Some of the combinations don't give an error, but they also don't find or replace anything. What's even worse is sometimes I get this other error.
find: paths must precede expression: index.html
How can the path precede the expression? . is the path, and it immediately follows the find command. It precedes all the expressions.
Try:
find . -name '*.html' -exec sed -i 's|{{\s*oldtag\s*}}|{{ newtag }}|g' {} +
With some assumptions:
your sed implementation recognizes the \s escape sequence and the -i option
your find implementation supports the {} + syntax
You should be escaping the ' and \ characters. This should work:
find . -name *.html -exec sed -i \'s/{{\\s*oldtag\\s*}}/{{ newtag }}/g\' {} \;
Tip: You can always just insert echo just before the word sed to see a printout of what it looks like (see what is escaped).