Mac: replace text inside files in directory using regular expression - regex

I need to replace all matches (regular expression) in directory from "*::" to be "\*::"
examples: (in multiple php files)
ID::
user::
process::
....
to be:
\ID::
\user::
\process::
I currently use,single commands
find . -type f -name '*.php' -exec sed -i '' s/ID::/\\\\ID::/ {} +
find . -type f -name '*.php' -exec sed -i '' s/user::/\\\\user::/ {} +
find . -type f -name '*.php' -exec sed -i '' s/process::/\\\\process::/ {} +
how to write regular expression to replace any "*::" => "\*::"
thanks,

You want to use "grouping" or "back-referencing" to refer back to a portion of the regular expression. This is done by surrounding the intended group with \( and \), and referring back to them with \1, \2, etc. In your case, the following expression should work:
$ echo -e "ID::\nuser::\nprocess::" | sed 's/\(.*\)::/\\\1::/g'
with the following output:
\ID::
\user::
\process::

I update "bebop" solution to meet my requirements, alot of thanks to him
solution:
sed -i -e 's/\([A-Za-z]*\)::/\\\1::/g' `grep -ril '::' *.php`

Related

How to recursively change files in directories whose name matches a string in Perl?

I have many directories for different projects. Under some project directories, there are subdirectories named "matlab_programs". In only subdirectories named matlab_programs, I would like to replace the string 'red' with 'blue' in files ending with *.m.
The following perl code will recursively replace the strings in all *.m files, regardless of what subdirectories the files are in.
find . -name "*.m" | xargs perl -p -i -e "s/red/blue/g"
And to find the full paths of all directories called matlab_programs,
find . -type d -name "matlab_programs"
How can I combine these so I only replace strings if the files are in a subdirectory called matlab_programs?
Perl has the excellent File::Find module, that lets you specify a callback to be called on each file.
So you can specified a complex compound criteria, like this:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
sub find_files {
next unless m/\.m\z/; # skip any files that don't end in .m
if ( $File::Find::dir =~ m/matlab_programs$/ ) {
print $File::Find::name, " found\n";
}
}
find( \&find_files, "." );
And then you can do whatever you wish with the files you find - like opening/text replacing and closing.
You want to find all directories named matlab_programs using
find . -type d -name "matlab_programs"
and then execute
find $f -name "*.m" | xargs perl -p -i -e "s/red/blue/g"
on all results $f. Judging by your use of xargs, there are no special characters such as spaces in your file names. so the following should work:
find `find . -type d -name "matlab_programs"` -name "*.m" |
xargs perl -p -i -e "s/red/blue/g"
or
find . -type d -name "matlab_programs" |
while read f
do
find $f -name "*.m" | xargs perl -p -i -e "s/red/blue/g"
done |
xargs perl -p -i -e "s/red/blue/g"
Incidentally, I'd use single quotes here; I always use them whenever the quoted string is to be taken literally.
Do you have bash? The $(...) syntax works like backticks (the way both the shell and Perl use them) but they can be nested.
perl -pi -e s/red/blue/g $(find $(find . -type d -name matlab_programs) -type f -name \*.m)
Many flavors of find also support a -path pattern test, so you can just combine your filename conditions into that argument
perl -pi -e s/red/blue/g $(find . -type f -path \*/matlab_programs/\*.m)

Regexp for matching filenames

I have a files:
first.error.log
second1.log
second2.log
FFFpc.log
TR.den.log
bla.error.log
and I would like to make a pattern that will match all files with error inside of filenames + few additional ones but no more:
For a sole error it would be
$FILE_PATTERN="*.error*"
But what if I want to match not only those errors but also all second and FFpc etc?
This does not work:
$FILE_PATTERN="*.error*|^second.*\log$|.*FFPC\.log$"
Thanks in advance for your help
EDIT:
$FILE_PATTERN is later used by:
find /somefolder -type f -name $FILE_PATTERN
EDIT: THIS FILE_PATTERN is in property file that is later used by bash script.
You need to use find with -regex option:
find -E /somefolder -type f -regex '\./(.*\.error.*|second.*log|.*FFPC\.log)$'
PS: Use -iregex for ignore case matching:
find -E /somefolder -type f -iregex '\./(.*\.error.*|second.*log|.*FFPC\.log)$'
$ ls | grep -i '\(.*error.*\)\|\(^second.*\log$\)\|\(.*FFPC\.log$\)'
bla.error.log
FFFpc.log
first.error.log
second1.log
second2.log
If you wanted to use with find
find /somefolder -type f | grep -i '\(.*error.*\)\|\(^second.*\log$\)\|\(.*FFPC\.log$\)'
If you're in bash I'm assuming you have to grep. Using grep -E or egrep will allow you to use alternation (ORing your searches)
$ stat * | egrep "(error|second)"
File: `first.error.log'
File: `second1.log'
File: `second2.log'
You could use ls instead of stat but sometimes ls will not give you what you predicted. But considering you're only search for filenames, ls should suffice.
$ ls | egrep "(error|second)"
first.error.log
second1.log
second2.log
You can use command substitution to store the output into a bash variable:
FILE_PATTERN=$(ls | egrep "(error|second)")
FILE_PATTERN=("*.error*" "second.*log" ".*FFPC.log")
ARGS=(-name "$FILE_PATTERN")
for F in "${FILE_PATTERN[#]:2}"; do
ARGS+=(-o -name "$F")
done
find /somefolder -type f '(' "${ARGS[#]}" ')'
You were close, theres just a few misplaced symbols.
Here's what I came up with:
.*\.error\..*|^second.*\.log$|.*FF[Pp][Cc]\.log$
here's a demo of a working modification of your regex:
http://regex101.com/r/rL3rM1/1

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.

Linux Command: Find & Replace using regex not woking as expected

I am trying to replace a path in all php files using regex command, but it isn't working as expected!
I want to replace '/home/example/public_html with $_SERVER['DOCUMENT_ROOT'] . '
I am using the below command in ssh:
find /var/www/advertise/ -name '*.php' -type f -exec sed -i 's/\'\/home\/example\/public_html/\$\_SERVER\[\'DOCUMENT\_ROOT\'\]\ \.\ \'/g' {} \;
When i enter the command and hit return, > sign follows like:
>
>
>
.. so on as i keep hitting return to execute the command.
Where as below command works perfectly (for replacing home/example/public_html with var/www):
find /var/www/advertise/ -name '*.php' -type f -exec sed -i 's/home\/example\/public_html/var\/www/g' {} \;
You're messing up with the quotes.
Use a separator other than / so that you don't need to escape the /
You don't need to escape in the replacement
Since you have ' in the replacement, better use "s#..#..#" (i.e. double quotes). However, you'll need to escape the $ in the replacement to prevent the shell from trying to expand.
The following might work for you:
find /var/www/advertise/ -name '*.php' -type f -exec sed -i "s#'/home/example/public_html#\$_SERVER['DOCUMENT_ROOT'] . '#g" {} \;

regextype with find command

I am trying to use the find command with -regextype but it could not able to work properly.
I am trying to find all c and h files send them to pipe and grep the name, func_foo inside those files. What am I missing?
$ find ./ -regextype sed -regex ".*\[c|h]" | xargs grep -n --color func_foo
Also in a similar aspect I tried the following command but it gives me an error like paths must precede expression:
$ find ./ -type f "*.c" | xargs grep -n --color func_foo
The accepted answer contains some inaccuracies.
On my system, GNU find's manpage says to run find -regextype help to see the list of supported regex types.
# find -regextype help
find: Unknown regular expression type 'help'; valid types are 'findutils-default', 'awk', 'egrep', 'ed', 'emacs', 'gnu-awk', 'grep', 'posix-awk', 'posix-basic', 'posix-egrep', 'posix-extended', 'posix-minimal-basic', 'sed'.
E.g. find . -regextype egrep -regex '.*\.(c|h)' finds .c and .h files.
Your regexp syntax was wrong, you had square brackets instead of parentheses. With square brackets, it would be [ch].
You can just use the default regexp type as well: find . -regex '.*\.\(c\|h\)$' also works. Notice that you have to escape (, |, ) characters in this case (with sed regextype as well). You don't have to escape them when using egrep, posix-egrep, posix-extended.
Why not just do:
find ./ -name "*.[c|h]" | xargs grep -n --color func_foo
and
find ./ -type f -name "*.c" | xargs grep -n --color func_foo
Regarding the valid paramters to find's option -regextype this comes verbatim from man find:
-regextype type
Changes the regular expression syntax understood by -regex and -iregex tests which occur later on
the command line. Currently-implemented types are emacs (this is the default),
posix-awk, posix-basic, posix-egrep and posix-extended
There is no type sed.