0

How do I remove all files not containing a specified text.

I understand the solution to remove files with a specified text, but I need to remove files NOT containing a specified pattern.

The following command creates a list of files not containing "successful run":

grep -c "successful run" *.out | grep -v ":1" > err.txt

I wish to directly delete these files.

4
  • Could one single .out file log both successful and unsucessful runs? Sep 27, 2019 at 18:15
  • @EduardoTrápani The right question for your case should be "could one single .out file contain at least one line with the pattern and at least one line without the pattern?" I can imagine there are two lines from one successful run (e.g. there's a timestamp in a separate line). Sep 27, 2019 at 18:39
  • @KamilMaciorowski, would you please let the OP answer the question I asked? Thanks. Sep 27, 2019 at 18:41
  • @EduardoTrápani My comment neither is able nor tries to stop the OP. It tries to convince you the answer you're hoping to get may not be able to support your current assumptions without additional assumption. The additional assumption is "successful run generates at most one line". Sep 27, 2019 at 18:47

2 Answers 2

0

Your original approach to identify appropriate files

grep -c "successful run" *.out | grep -v ":1"

is flawed. Main concerns:

  • What if there are two or more matching lines in one file? grep ":0" seems to fit the condition in the title of your question better ("files not containing a pattern").
  • What if :1 (or :0) is in the filename? So grep ':0$' seems even better.
  • What if there's a newline character in any filename passed from the first grep?

I say do not rely on grep -c; rely on the exit status from grep which is 1 if no lines were selected.

for f in *.out; do
   [ -f "$f" ] && {
      grep -q -- "successful run" "$f"
      [ "$?" -eq 1 ] && rm -i -- "$f"
   }
done

Notes:

  • [ -f "$f" ] && … will not let grep work with directories, fifos etc. that match *.out; only regular files.
  • The meaning and significance of -- is explained here. It's in case there's a file with name starting with -, it can be mistaken for an option. Another way to deal with this problem is for f in ./*.out; do …. This way every expanded $f starts with ./ so it cannot start with -.
  • I used rm -i just in case. After you test the solution you may want to omit -i.
  • grep … || rm … is worse. When a real error occurs (e.g. permission denied) the exit status of grep is greater than 1; you probably don't want to remove the file then. My solution tests if the exit status is exactly 1.
  • Your original code doesn't descend into subdirectories, neither does mine. If you want recursion then a shell that supports it (e.g. Bash with shopt -s globstar and **) or a solution based on find will be useful.
-1

Considering that your files have either a single "successful run" or none, then:

to find the matching files you can do:

grep -l "successful run" *.out > err.txt

to find and remove them:

grep -l "successful run" *.out | xargs rm

to find the files without match you then do:

grep -vl "successful run" *.out > ok.txt

to find and remove them:

grep -vl "successful run" *.out | xargs rm

The flags mean:

-l lists the files with matches
-v/--invert-match inverts the matching logic
7
  • 1
    -1. grep -v does not find "files without matches". It finds "files with lines without matches". It can be grep -l foo and grep -vl foo both print the same file because there is a line with foo and another line without foo in the file. Sep 27, 2019 at 17:48
  • You are confusing lines and files. If 'foo' is in the file anywhere then grep -l foo file will list it. If is not anywhere, then it will be listed by grep -vl foo file'. But feel free to come up with two files that will be simultaneously listed with grep -vl pattern` and grep -l pattern. Good luck. Sep 27, 2019 at 17:56
  • 1
    printf '%s\n' foo bar > test; grep -l foo test; grep -vl foo test. Both greps will list the same file. Sep 27, 2019 at 18:00
  • Because it IS the same file. Did you read what I wrote? "come up with two files that..." Good try though :) Sep 27, 2019 at 18:07
  • 1
    OK. Run the same command but name the file test2. Now there are two files. What's your point? My point is grep -vl… may find files with matches. This is not a right way to find files totally without matches. Sep 27, 2019 at 18:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .