Find and Replace string in all files recursive issue - bash

I try this command to find and replace string in my android project.
find . -name '*.java' -print0 | xargs -0 sed -i "" "s;//\#Logger\.;Logger\.;g"
//#Logger. => Logger.
It's work but in some files i have unexpected changes. With git diff i get:
-}
\ No newline at end of file
+}
How to fix it?

Well, just figured out the problem.
Your code should work as following (remove redundand "" after -i in sed):
find . -name '*.java' -print0|xargs -0 sed -i "s;//\#Logger\.;Logger\.;g"
Alternatively you can use parallel instead xargs and run this even faster:
find . -name '*.java' -print0|parallel -0 sed -i "s;//\#Logger\.;Logger\.;g" {}
And suggested below find .. -exec variant:
find . -name '*.java' -exec sed -i "s;//\#Logger\.;Logger\.;g" {} +;

Related

renaming series of files using xargs

I would like to rename several files picked by find in some directory, then use xargs and mv to rename the files, with parameter expansion. However, it did not work...
example:
mkdir test
touch abc.txt
touch def.txt
find . -type f -print0 | \
xargs -I {} -n 1 -0 mv {} "${{}/.txt/.tx}"
Result:
bad substitution
[1] 134 broken pipe find . -type f -print0
Working Solution:
for i in ./*.txt ; do mv "$i" "${i/.txt/.tx}" ; done
Although I finally got a way to fix the problem, I still want to know why the first find + xargs way doesn't work, since I don't think the second way is very general for similar tasks.
Thanks!
Remember that shell variable substitution happens before your command runs. So when you run:
find . -type f -print0 | \
xargs -I {} -n 1 -0 mv {} "${{}/.txt/.tx}"
The shell tries to expan that ${...} construct before xargs even
runs...and since that contents of that expression aren't a valid shell variable reference, you get an error. A better solution would be to use the rename command:
find . -type f -print0 | \
xargs -I {} -0 rename .txt .tx {}
And since rename can operate on multiple files, you can simplify
that to:
find . -type f -print0 | \
xargs -0 rename .txt .tx

issue with piping find into sed (find and replace)

Here is my current code, my goal is to find every file in a given directory (recursively) and replace "FIND" with "REPLACEWITH" and overwrite the files.
FIND='ALEX'
REPLACEWITH='<strong>ALEX</strong>'
DIRECTORY='/some/directory/'
find $DIRECTORY -type f -name "*.html" -print0 |
LANG=C xargs -0 sed -i "s|$FIND|$REPLACEWITH|g"
The error I am getting is:
sed: 1: "/some/directory ...": command a expects \ followed by text
As given in BashFAQ #21, you can use perl to perform search-and-replace operations with no potential for data being treated as code:
in="$FIND" out="$REPLACEWITH" find "$DIRECTORY" -type f -name '*.html' \
-exec perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' '{}' +
If you want to include only files matching the FIND string, find can be told to only pass files which grep flags on to perl:
in="$FIND" out="$REPLACEWITH" find "$DIRECTORY" -type f -name '*.html' \
-exec grep -F -q -e "$FIND" '{}' ';' \
-exec perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' '{}' +
Because grep is being used to evaluate individual files, it's necessary to use one grep call per file so its exit status can be evaluated on a per-file basis; thus, the use of the less efficient -exec ... {} ';' action. For perl, it's possible to put multiple files to process on one command, hence the use of -exec ... {} +.
Note that fgrep is line-oriented; if your FIND string contains multiple lines, then files with any one of those lines will be passed to perl for replacements.
You can have find invoke sed directly although I think all the modification times on your files will be affected (which might matter or not):
find $DIRECTORY -type f -name "*.html" -exec sed -i "s|$FIND|$REPLACEWITH|g" '{}' ';'

sed: -i may not be used with stdin #Error

I'm getting an error with the following
find . -name "*" -type f | xargs grep -l "xyz" | sed -i '' 's/'${line}'/'${rep}'/g'
sed: -i may not be used with stdin
what's gone wrong?
Asuming that you're trying to sed something only in the files that contain xyz, you will have to xargs again
find . -name "*" -type f | xargs grep -l "xyz" |xargs sed -i "s/'${line}'/'${rep}'/g"
-i is for inline file editing and you are just piping find command's output to sed in stdin hence that error shows up.
Try this find command instead:
find . -name "*" -type f -exec sed -i '' "s/${line}/${rep}/g" '{}' \;
PS: -name "*" can also be skipped here.
When we are using the find command we can't connect the output with the pipe( | ). So you can use the -exec with find command to execute more commands.

how do i convert tabs to spaces on many files with bash

How can I convert tabs to spaces in in all .js files in a directory in one command?
find . -type f -iname "*.js" -print0 | xargs -0 -I _FILE_ tab2space _FILE_ _FILE_
This would convert tabs to four spaces:
find /path/to/directory -type f -iname '*.js' -exec sed -ie 's|\t| |g' '{}' \;
Change the space part in sed between the next two | to have a custom number of spaces you like.
Another way is to process all files to one sed call at once with +:
find /path/to/directory -type f -iname '*.js' -exec sed -ie 's|\t| |g' '{}' '+'
Just consider the possible limit of arguments to a command by the system.
Simpler syntax:
for F in *.js; do sed -iE 's|\t| |g' $F; done
(Caution, edits files in place.) Could be made to rename edited copy, or placed into a function if you do this often.

Shell Scripting: Using bash with xargs

I'm trying to write a bash command that will delete all files matching a specific pattern - in this case, it's all of the old vmware log files that have built up.
I've tried this command:
find . -name vmware-*.log | xargs rm
However, when I run the command, it chokes up on all of the folders that have spaces in their names. Is there a way to format the file path so that xargs passes it to rm quoted or properly escaped?
Try using:
find . -name vmware-*.log -print0 | xargs -0 rm
This causes find to output a null character after each filename and tells xargs to break up names based on null characters instead of whitespace or other tokens.
Do not use xargs. Find can do it without any help:
find . -name "vmware-*.log" -exec rm '{}' \;
Check out the -0 flag for xargs; combined with find's -print0 you should be set.
find . -name vmware-*.log -print0 | xargs -0 rm
GNU find
find . -name vmware-*.log -delete
find . -name vmware-*.log | xargs -i rm -rf {}
find -iname pattern
use -iname for pattern search
To avoid space issue in xargs I'd use new line character as separator with -d option:
find . -name vmware-*.log | xargs -d '\n' rm

Resources