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.txtI wish to directly delete these files.
42 Answers
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? Sogrep ':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" }
doneNotes:
[ -f "$f" ] && …will not letgrepwork 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 isfor f in ./*.out; do …. This way every expanded$fstarts with./so it cannot start with-. - I used
rm -ijust 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 ofgrepis greater than1; you probably don't want to remove the file then. My solution tests if the exit status is exactly1.- 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 globstarand**) or a solution based onfindwill be useful.
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.txtto find and remove them:
grep -l "successful run" *.out | xargs rmto find the files without match you then do:
grep -vl "successful run" *.out > ok.txtto find and remove them:
grep -vl "successful run" *.out | xargs rmThe flags mean:
-l lists the files with matches
-v/--invert-match inverts the matching logic 7