Find string inside files and replace with a new string - bash

I need to find all files containing certain text inside my project directory.
This includes sub-directories.
I've managed to find all the files:
find . -type f -exec grep -H 'Rename' {} \;
Now I need to replace the keyword "Rename" with "XYZ" leaving the rest of text in each file intact.
Ideas?

sed instead of grep.
find . -type f -exec sed -i 's/Rename/XYZ/g' {} \;
grep already scans all the lines of every file, so you aren't losing anything. This just makes the change when it finds it, instead of printing out the line.

Related

How to add a line in files recursively bash?

I use the command to add one line at the beginning of the php files in the current directory and its subdirrectories recursively.
find . -name "*.php" -exec sed -i -e "/<?php/a\\
Sometext" *.php \;
But it adds Sometext many times (instead of one) only in php files in the current directory (instead of all). What I did wrong?
You don't pass the files found by find to the sed command, but the files found by the shell glob *.php. Before find is executed, the *.php is expanded and your command becomes
find . -name '*.php' -exec sed ... 1stMatch.php 2ndMatch.php ... \;
Afterwards, find will for each found file execute the command
sed ... 1stMatch.php 2ndMatch.php ...
You probably wanted to write
find . -name '*.php' -exec sed -i -e '/<?php/a\\
Sometext' {} \;
For each file, find executes sed and replaces {} by one file name.
In this case, you could even write {} + instead of {} \; such that sed is executed only once on all files at once, instead of once for every file – this will speed up your command drastically.

Get all occurrences of a string within a directory(including subdirectories) in .gz file using bash?

I want to find all the occurrences of "getId" inside a directory which has subdirectories as follows:
*/*/*/*/*/*/myfile.gz
i tried thisfind -name *myfile.gz -print0 | xargs -0 zgrep -i "getId" but it didn't work. Can anyone tell me the best and simplest approach to get this?
find ./ -name '*gz' -exec zgrep -aiH 'getSorById' {} \;
find allows you to execute a command on the file using "-exe" and it replaces "{}" with the file name, you terminate the command with "\;"
I added "-H" to zgrep so it also prints out the file path when it has a match, as its helpful. "-a" treats binary files as text (since you might get tar-ed gzipped files)
Lastly, its best to quote your strings in case bash starts globbing them.
https://linux.die.net/man/1/grep
https://linux.die.net/man/1/find
Use the following find approach:
find . -name *myfile.gz -exec zgrep -ai 'getSORByID' {} \;
This will print all possible lines containing getSORByID substring

How do I recursively find files with specific names and join using ImageMagick in Terminal?

I have created an ImageMagick command to join images with certain names:
convert -append *A_SLIDER.jpg *B_SLIDER.jpg out.jpg
I have lots of folders with files named *A_SLIDER.jpg and *B_SLIDER.jpg next to each other (only ever one pair in a directory).
I would like to recursively search a directory with many folders and execute the command to join the images.
If it is possible to name the output image based on the input images that would be great e.g.
=> DOGS_A_SLIDER.jpg and DOGS_B_SLIDER.jpg would combine to DOGS_SLIDER.jpg
Something like this, but back up first and try on a sample directory only!
#!/bin/bash
find . -name "*A_SLIDER*" -execdir bash -c ' \
out=$(ls *A_SLIDER*);
out=${out/_A/}; \
convert -append "*A_SLIDER*" "*B_SLIDER*" $out' \;
Find all files containing the letters "A_SLIDER" and go to the containing directory and start bash there. While you are there, get the name of the file, and remove the _A part to form the output filename. Then execute ImageMagick convert with the _A_ and the corresponding _B_ files to form the output file.
Or, a slightly more concise suggestion from #gniourf_gniourf... thank you.
#!/bin/bash
find . -name "*A_SLIDER.jpg" -type f -execdir bash -c 'convert -append "$1" "${1/_A_/_B_}" "${1/_A/}"' _ {} \;
The "find" command will recursively search folders:
$ find . -name "*.jpg" -print
That will display all the filenames. You might instead want "-iname" which does case-insensitive filename matching.
You can add a command line with "-exec", in which "{}" is replaced by the name of the file. You must terminate the command line with "\;":
$ find . -name "*.jpg" -exec ls -l {} \;
You can use sed to edit the name of a file:
$ echo DOGS_A_SLIDER.jpg | sed 's=_.*$=='
DOGS
Can you count on all of your "B" files being named the same as the corresponding "A" files? That is, you will not have "DOGS_A_SLIDER.jpg" and "CATS_A_SLIDER.jpg" in the same directory. If so, something like the following isn't everything you need, but will contribute to your solution:
$ find . -type f -name "*.jpg" -exec "(echo {} | sed 's=_.*==')" \;
That particular sed script will do the wrong thing if you have any directory names with underscores in them.
"find . -type f" finds regular files; it runs modestly faster than without the -type. Use "-d" to find directories.

using output of grep command to find command

I have a problem related to searching a pattern among several files.
I want to search "Logger." pattern in jsp files,so i used the command
grep -ir Logger. * | find . -name *.jsp
Now the problem i am facing is that this command is listing all the jsp files and its not searching the pattern "Logger." in jsp files and listing them.
I just want the jsp files in which "Logger." instance is present.
start like this
you want to search in jsp files.
find . -name "*.jsp"
the above will output all the jsp files recursively from current directory. like below
1/2/ahbd.jsp
befwej/dg/wefwefw/wefwefwe/ijn.jsp
And now you want to find the string in just these files.
grep -ir Logger. (output of find)
so the actual complete command becomes:
find . -name "*.jsp"|xargs grep -ir 'Logger.'
magic here is done by xargs
it gives the output of find as an input for grep line by line.
if you remove xargs,then only the first line that is 1/2/ahbd.jsp will be searched for the string.
there are several other ways to do this.But i feel more comfortable using this regularly
To recursively find all *.jsp files containing the string Logger. you can do:
find . -type f -name '*.jsp' -exec grep -l "Logger\." {} \;
grep -l means to print only the file name if the file contains the string.
The -exec switch of find will execute the given command for each file matching the other criteria (-type f and -name '*.jsp'). The string {} is substituted by the filename. Some versions of find also support + instead of {} to feed several file names to the command (like xargs does) and not only one at once, e.g.:
find . -type f -name '*.jsp' -exec grep -l "Logger\." + \;
You can just use grep for that, here's a command that should give you the results:
grep -ir "Logger\." * | grep ".jsp"
Problem is, grep will bail when you use ".jsp" instead or "" if you don't have at least one .jsp file into your root directory. So we have to tell him to look every file.
Since you give grep the -r (recursive) argument, it will walk the subdirectories to find the pattern "Logger.", then the second grep will only display the .jsp files. Note that -i tells grep not to care about the letter case, which is may be not what you want.
edit: following John's answer: we have to escape the . to prevent it to be taken as a regexp.
re-edit: actually, I think that using find is better, since it will filter the jsp files directly instead of grepping all the files:
find . -name "*.jsp" -exec grep -i "Logger\." {} \;
(you don't need the -r anymore since find takes care of recursion.
If you have bash 4+
shopt -s globstar
shopt -s nullglob
for file in **/*.jsp
do
if grep -q "Logger." "$file" ;then
echo "found in $file"
fi
# or just grep -l "Logger." "$file"
done

Shell script traversing the all subdirectories and modifying the content of files

I need to modify a number of files inside a directory. I need to modify all those files which contain particular text and have to replace with some new text.
So I thought of writing a shell script which will traverse through all the subdirectories and modify the content but I'm having problem while traversing the all possible directories.
You can use find to traverse through subdirectories looking for files and then pass them on to sed to search and replace for text.
e.g.
find /some/directory -type f -name "*.txt" -print -exec sed -i 's/foo/bar/g' {} \;
will find all txt files and replace foo with bar in them.
The -i makes sed change the files in-place. You can also supply a backup-suffix to sed if you want the files backed up before being changed.
GNU find
find /some_path -type f -name "*.txt" -exec sed -i 's/foo/bar/g' "{}" +;
http://git.savannah.gnu.org/cgit/bash.git/tree/examples/functions/recurse
:)
You want find.
for n in $(find | grep txt$)
do
echo $n
modify_content.sh $n
done

Resources