sed replace string with string containing dash in all files in folder - regex

In all files in a fodler, I am trying to replace all strings of the type:
load(alpha)
to
load(alpha, lib="lib=~/project-a/alpha")
using sed I tried:
find . -type f -print0 | xargs -0 sed -i 's/load(alpha)/load(alpha, lib="lib=~/project-a/alpha")/g'
But I get the error:
sed: -e expression #1, char 39: unknown option to `s'
Any idea what I am missing?
Thank you!

You get that error because the / delimiters with the substitute command are conflicting with the directory separators in your replacement; after the first directory separator is encountered, sed considers the replacement aborted. Change your delimiter to something else for a more clearer command.
sed -i 's!load(alpha)!load(alpha, lib="lib=~/project-a/alpha")!g'

find . -type f -print0 | xargs -0 sed -i 's/load(alpha)/load(alpha, lib="lib=~\/project-a\/alpha")/g'
In your command the character / is tehe delimiter, so you need to escape any forward-slashes that are part of your data as in /project-a/alpha -> \/project-a\/alpha
Alternatively you can a different delimiter (in this case the # character)
find . -type f -print0 | xargs -0 sed -i 's#load(alpha)#load(alpha, lib="lib=~/project-a/alpha")#g'

Related

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.

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 {} +

sed search replace pattern

I have files with below text (and more).
import (
"http"
"web"
)
I want to replace all "web" with "pkg/web" (in all files). so the outcome needs to
import (
"http"
"pkg/web"
)
I try sed like
find . -type f -print0 | xargs -0 sed -i '/"web"/c\"pkg/web"'
which gives error.
sed: 1: "test" invalid command code .
what is the correct way?
Thanks.
Problem is that you're using / as regex delimiter but also using / in your replacement string.
Good news is that sed allows different regex delimiters.
This sed with a different regex delimiter should work:
sed -i.bak 's~^\( *\)"web" *$~\1"pkg/web"~g'
UPDATE: To preserve whitespace on LHS of searched string:
find . -type f -print0 | xargs -0 sed -i '' 's~^\([[:space:]]*\)"web"[[:space:]]*$~\1"pkg/web"~g'
find . -type f -print0 | xargs -0 sed -i -e 's#"web"#"pkg/web"#g'
This works fine for me.

how can I make this sed capture accomplish a more complex substitution

when fixing mass spelling errors in my code base i have used this:
find . -path '*/.svn' -prune -o -name "*min.js" -prune -o -name "*min.css" -prune -o -name "flashLocaleXml.xml" -prune -o -type f -print0 | xargs -0 egrep -n "priority=" -exec sed -i 's/replace/newval/' {} \;
to fix a specific spelling error in all the files in my repo.
however, i am not very good with sed captures, i want to do something like:
X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);
becomes:
EventUtil.addEventListener(X, LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);
I have read up extensively but I would appreciate someone explaining how sed captures work with this as a specific example.
I have given it a few shots, but nothing I come up with works: here are my tries
echo "X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);" | sed 's/\(.*\)EventUtil\(.*EventUtil\)/\1X\2/'
echo "X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);" | sed -r 's/(....),(....),(*\.addEventListener)(LevelUpEvent.*)/\1,\2\n\1,\2,/g'
echo "X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);" | sed 's/\([\.$]*\) \([\.$]*\)/\2 \1/'
thank you in advance!
Try with:
sed 's/\([^.]*\)\([^(]*(\)/EventUtil\2\1, /'
Output:
EventUtil.addEventListener(X, LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);
Explanation:
\([^.]*\) # Content until first '.'
\([^(]*(\) # Content until first '('
EventUtil\2\1, # Literal 'EventUtil' plus grouped content in previous expression.
This sed command will do.
sed 's/\(X\).\(addEventListener\)(\(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels\));/EventUtil.\2(\1, \3);/'
Example
$ echo "X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);" | sed 's/\(X\).\(addEventListener\)(\(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels\));/EventUtil.\2(\1, \3);/'
EventUtil.addEventListener(X, LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);
Try this
echo "X.addEventListener(LevelUpEvent.GENERIC_LEVEL_UP, updateLevels);" | sed -e "s/\([A-Za-z]\{1,\}\)\.addEventListener(/EventUtil.addEventListener(\1, /"
This regexp will recognize a variable name using
\([A-Za-z]\{1,\}\)
Then .addEventListener(
\.addEventListener(
And replace it with
EventUtil.addEventListener(\1
In which \1 represents the variable name

Using grep to search files provided by find: what is wrong with find . | xargs grep '...'?

When I use the command:
find . | xargs grep '...'
I get the wrong matches. I'm trying to search for the string ... in all files in the current folder.
As Andy White said, you have to use fgrep in order to match for plain ., or escape the dots.
So you have to write (-type f is to only have the files : you obviously don't want the directories.) :
find . -type f | xargs fgrep '...'
or if you still want to use grep :
find . -type f | xargs grep '\.\.\.'
And if you only want the current directory and not its subdirs :
find . -maxdepth 1 -type f | xargs fgrep '...'
'.' matches any character, so you'll be finding all lines that contain 3 or more characters.
You can either escape the dots, like this:
find . | xargs grep '\.\.\.'
Or you can use fgrep, which does a literal match instead of a regex match:
find . | xargs fgrep '...'
(Some versions of grep also accept a -F flag which makes them behave like fgrep.)
#OP, if you are looking for files that contain ...,
grep -R "\.\.\." *
If you're looking for a filename that matches, try:
find . -name "filename pattern"
or
find . | grep "filename pattern"
If your looking for looking for files that match (ie it contains the grep string)
find . | xargs grep "string pattern"
works fine. or simply:
grep "string pattern" -R *
If you are literally typing grep '...' you'll match just about any string. I doubt you're actually typing '...' for your grep command, but if you are, the ... will match any three characters.
Please post more info on what you're searching for, and maybe someone can help you out more.
To complete Jeremy's answer, you may also want to try
find . -type f | xargs grep 'your_pattern'
or
find . -type f -exec grep 'your_pattern' {} +
Which is similar to a xargs
I might add : RTFM ! Or in a more polite way : use & abuse of
man command
!