Suppose there are two files in web/ named foo.php and bar.php. The 1st line of foo.php is "sdajgeSTRINGdsad" and the 10th line of bar.php is "gdfhu98324STRING". The task is to first locate these two files, then delete 1st line of foo.php and 10th line of bar.php given that the specified string is "STRING".


sed can do that :

sed -i.bak '/STRING/d' web/*
|improve this answer|||||
  • Thanks, tuxce. How ever it does not work as expected. Should I remove the "*" at the end in order to recursively search all files and subfolders under web? – Covi Jul 28 '11 at 8:02
  • 2
    @ZonghengYang: To recursivly search with this method you will have to change your shell globing method so you can use **, a glob that matches recursively. First run this: shopt -s extglob, then use web/**. – Caleb Jul 28 '11 at 8:10
  • This will create backup files of every file matching the glob even if a match not found and no change is made to the file! If you want be more judicious you will have to do the file and edit operations in separate steps. – Caleb Jul 28 '11 at 8:14
  • 2
    Try: grep -Zlr STRING web | xargs -0 sed -i.bak '/STRING/d' (Edit: I didn't see previous comment, extglob saves 2 process) – tuxce Jul 28 '11 at 8:16
  • @tuxce: It saves two processes and makes a mess of the directory and wastes a lot of disk space. Note that sed makes backups even if it doesn't change anything in a file. Your grep | xargs sed is a better solution, and does basically what I wrote a function for. – Caleb Jul 28 '11 at 8:46

To find a file containing a string, use grep. If you want to find which files contain STRING in web/ and all subdirectories:

grep -R "STRING" web/

To edit a file and remove lines containing a string, there are many options but here are two common ones. Since you want to operate on entire lines this is really easy :)

First you could use grep with the -v argument to reverse the search and hide the matched lines from the output instead of showing them. For your first file, let's do this using sponge. This will allow us to read your file, filter it, then write it back to the same file all in one motion:

grep -v "sdajgeSTRINGdsad" foo.php | sponge foo.php

For your second example we'll do the same thing with grep, but if you don't have sponge you can write it to a different file, then move that file back to the original name:

grep -v "gdfhu98324STRING" bar.php  > bar.php.cleaned
mv bar.php{.cleaned,}

The second way would be to use sed with the d line delete command. For your first example we will use the in-place file edit with the option to create a .bk backup file:

sed -i.bk '/sdajgeSTRINGdsad/d'  foo.php

Pretty much the same thing could be accomplished by copying the file yourself then using sed to filter the backup and over-write the original:

cp bar.php bar.php.bk
sed '/gdfhu98324STRING/d' bar.php.bk > bar.php

Now to combine these two tasks! Let's make a function so you can do this repeatedly with different strings:

function nuke_string () {
    grep -R -l "$string" "$path" | while IFS= read -r file; do
        sed -i.bk "/$string/d" "$file"

Once you create that function, you could use it like this:

nuke_string "STRING" web/

Any files containing STRING in web/ would then have those lines removed and a backup copy would be made of the original version. You can create a function like this in your current shell or you can write it to your .bashrc file and have it always available.

|improve this answer|||||
  • Thank you, Caleb. I think I have to apologize for I have not made myself clear. My problem is that I don't know which files (and how many of them) contain a specified string, which is exactly "STRING" but not "gdfhu98324STRING" or "sdajgeSTRINGdsad". So the method has to first locate or find those files that contain the string, then modify them. – Covi Jul 28 '11 at 7:49
  • @ZonghengYang: Ya sorry I missed the big about finding the files until I went to edit your question to clean it up. See my edited answer. – Caleb Jul 28 '11 at 7:58

Just make use of grep -l together with -R! Here's a complete one-liner:

grep -Rl "STRING" web/ | xargs sed -i "/STRING/d"
|improve this answer|||||
  • With the usual dangers of xargs, i.e. it won't work if any of the file names contains whitespace or \'". – Gilles 'SO- stop being evil' Jul 29 '11 at 11:33
  • @Gilles, True, but it should not be a problem in a sane directory tree as I understand web/ should be. – rozcietrzewiacz Jul 29 '11 at 11:35
  • Well for more safer side, you should also include file-type check, so it is removed only from those type of files, example '.csv' – Vicky Dev Aug 30 '16 at 5:09

There are two alternatives:

  1. use find to recursively locate your files (e.g. *.php files) and perl or GNU flavor of sed (both have the -i option) for performing the deletion.

  2. What you are asking for looks like a refactoring operation: change the name of an element of code everywhere in the codebase. If my guess is correct, you should check IDEs able to handle php development.

|improve this answer|||||
  • find is not an appropriate tool to find files based on their contents, which is what the OP is asking here. It works best to identify files by their properties. – Caleb Jul 28 '11 at 8:48
  • I didn't mean to use find for filtering by contents, but by file extension. I assumed that what interests OP is locating php files, that are more likely to contain STRING, then apply the sed command for deleting matching lines. – mouviciel Jul 28 '11 at 8:58

You can use Vim in Ex mode:

for k in web/*.php
  ex -sc '/STRING/d|x' "$k"
  1. d delete

  2. x save and close

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.