Linux grep and delete files

Delete a list of files with find and grep

I want to delete all files which have names containing a specific word, e.g. «car». So far, I came up with this:

12 Answers 12

or pass the output of your pipeline to xargs :

find | grep car | xargs rm -f 

Note that these are very blunt tools, and you are likely to remove files that you did not intend to remove. Also, no effort is made here to deal with files that contain characters such as whitespace (including newlines) or leading dashes. Be warned.

+1. But on the first few runs: change «rm» to «echo rm» . and verify that it only outputs file you really want to delete, and no others ^^

@nhahtdh: xargs: illegal option — d ; all the world is not LInux. And what about directories that contain \n in their name? If you worry about whitespace, you should use find —print0 . xargs -0

Please be aware that this will not work if your files contain unusual characters (like spaces) or start with a dash. Please see my answer for a fix.

To view what you are going to delete first, since rm -fr is such a dangerous command:

find /path/to/file/ | grep car | xargs ls -lh 

Then if the results are what you want, run the real command by removing the ls -lh , replacing it with rm -fr

find /path/to/file/ | grep car | xargs rm -fr 

It does exactly what you ask, logically running rm -rf on the what grep car returns from the output of find . which is a list of every file and folder recursively.

You really want to use find with -print0 and rm with — :

find [dir] [options] -print0 | grep --null-data [pattern] | xargs -0 rm -- 

A concrete example (removing all files below the current directory containing car in their filename):

find . -print0 | grep --null-data car | xargs -0 rm -- 
  • -print0 , —null-data and -0 change the handling of the input/output from parsed as tokens separated by whitespace to parsed as tokens separated by the \0 -character. This allows the handling of unusual filenames (see man find for details)
  • rm — makes sure to actually remove files starting with a — instead of treating them as parameters to rm . In case there is a file called -rf and do find . -print0 | grep —null-data r | xargs -0 rm , the file -rf will possibly not be removed, but alter the behaviour of rm on the other files.

Источник

On Linux, how can I find all files that contain a string and delete them?

Please clarify: do you want to delete files whose name contains foo (e.g. myfoo.jpg ), or files that contain the byte sequence foo (which may include binary files which just so happen to contain that sequence of bytes)?

3 Answers 3

grep -lrIZ foo . | xargs -0 rm -f -- 
  • -l prints file names of files matching the search pattern.
  • -r performs a recursive search for the pattern foo in the given directory . . If this doesn’t work, try -R .
  • -I (capital i ) causes binary files like PDFs to be skipped.
  • -Z ensures that file names are zero- (i.e., nul-)terminated so that a name containing white space does not get interpreted in the wrong way (i.e., as multiple names instead of one).
  • xargs -0 feeds the file names from grep to rm -f , separating words by zero (nul) bytes (remember the -Z option from grep ).
  • — is often forgotten but it is very important to mark the end of options and allow for removal of files whose names begin with — .
Читайте также:  Linux как установить nginx

If you would like to see which files are about to be deleted, simply remove the | xargs -0 rm -f — part, and leave off the Z option to grep .

Another user suggested something like the following, which you should not run because it is unsafe:

files=`grep foo * | cut -d: -f1` rm -f $files # unsafe, do not run it! 

If I have files ImportantStuff that I do not want to delete and obsolete ImportantStuff containing foo , then I lose ImportantStuff (and not obsolete ImportantStuff !) when I run this command, because $files gets broken apart at spaces when it is interpreted. It is dangerous to put a list of filenames into a scalar shell variable in this way.

Источник

Delete files with specific content

The output of grep would include the filename and the line containing the string so instead of passing it to rm , it would just run the rm command on * which is everything in the directory and it would delete the files and give an error for directories because the -r switch isn’t used. Do you want to delete the files that have that string in their contents? If so, provide an example of what it might look like. Do you also want to delete files that have Key = 01 or MyKey = 05 ?

2 Answers 2

You can use the following command in the shell. This should do the job if pattern to be searched is Key = 0

grep -lrIZ "Key = 0" . | xargs -0 rm -f -- 
grep -lrIZ "" . | xargs -0 rm -f -- 

The main issue with the pipeline using grep + rm is that rm does not read from its standard input stream, which means that it does not read anything from the grep command on the left-hand side of the pipe.

Instead, the rm * on the right-hand side of the pipe would ignore all input and execute rm on every visible filename in the current directory.

Ignoring the issue with rm not reading its standard input, your grep command has two main issues:

  1. It outputs matching lines with filenames. This would be of no use to rm as we need to know only the filenames of the files we want to delete.
  2. It matches Key = 0 as a substring, which means it also matches Crypto Key = 0x01 etc.
find . -type f -exec grep -q -F -x 'Key = 0' <> \; -exec rm -f <> + 

or, with GNU find (and some others),

find . -type f -exec grep -q -F -x 'Key = 0' <> \; -delete 

Both of these would look for regular files in the current directory or below, and for each found file, it would execute grep -q -F -x ‘Key = 0’ . This grep command would return an exit status signalling whether there is a line in the file that is exactly Key = 0 (and nothing else).

The second find command will delete the file using its -delete predicate if such a line is found. The first find command would collect the pathnames of the files containing this line and then run rm -f on batches of these.

Читайте также:  Установка gdebi astra linux

The flags used with grep are

  • -q , for quiet operation. The utility does not output matching lines but exits successfully after the first match or with a non-zero exit status if the file does not contain a match.
  • -F , for fixed string matching. We are matching with a string, not a regular expression.
  • -x , to find full-line matches only. This has the same effect as if using a regular expression anchored to both the start and end of the line.

I’m not using -i with grep here as that would also delete files containing lines like KEY = 0 and kEY = 0 etc., and you have said nothing about these case variations.

Would you want the find command to be restricted to a particular filename suffix, like .ext , then use -name ‘*.ext’ in the find command before the execution of grep . For example:

find . -name '*.ext' -type f -exec grep -q -F -x 'Key = 0' <> \; -exec rm -f <> + 

Источник

Linux command to find and delete Files which contain a given text

The command I’m looking for will delete the files: file-1.php and file-3.html .

UPDATE: The file should delete the file ONLY IF «extract($_REQUEST)» is the only line of text in the file. See the examples below:

  • file-4.php : This file JUST contains the text «extract($_REQUEST)»
  • file-5.php : This file contains the text «extract($_REQUEST)» and other lines of text

Then command will delete file-4.php and will not delete file-5.php .

3 Answers 3

find . -maxdepth 1 -type f \ -exec fgrep -q 'extract($_REQUEST)' '<>' ';' \ -not -exec fgrep -vq 'extract($_REQUEST)' '<>' ';' \ -delete 
  • find . search the current directory
  • -maxdepth 1 and no subdirectories
  • -type f finding files
  • -exec and for each execute this test
    • fgrep a plain string search
      • -q with no visible output
      • ‘extract($_REQUEST)’ for this string
      • ‘<>‘ in the file you found
      • ‘;’ [end of exec]
      • -exec exec again
        • fgrep fgrep again
          • -vq but this time look for non-matching lines
          • ‘extract($_REQUEST)’ same pattern to look for
          • ‘<>‘ in the file

          This works because exec is also a test and when fgrep finds a match the the test succeeds and the delete runs. if grep returns false the delete is not done.

          @Jasen Not really. Just change your grep to ! -exec grep -q -v -Fx ‘. ‘ <> \; (you may want to test that first though)

          grep -FRl 'extract($_REQUEST)' | xargs rm -fv 
          • grep — search text in files.
          • -F — treat the string as is, ignore possible regular expressions.
          • -R — recursive search.
          • -l — only print filenames.
          • xargs — give the output to the next program.
          • rm — remove.
          • -f — force (don’t ask «Are you sure?»).
          • -v — is optional, it will pring the files that were removed.

          In order to delete only the files with exact text, I suggest checking the amount of characters in the file as well.

          for i in $(grep -FRl 'extract($_REQUEST)'); do [[ $(cat $i | wc -c) == "19" ]] && rm -fv $i; done 
          • wc -c — counts the characters in the file. Since the example you provided ( extract($_REQUEST) ) is 19 characters long (that includes newline character), I used this number in my example, feel free to change it to fit your situation.

          @Jasen I can’t think of a scenario that will fail with my command. You grep for a very specific string that is n characters long. And you check if the lengh of the file is n characters. If its not the only line, the check will fail. I believe its sophisticated enough, but if you can give me an example of false positive check, I will be grateful.

          find . -maxdepth 1 -type f -exec grep -l "string_to_be_searched" <> \;|awk ''| sed "s/\.\///g"| awk ''| sh 

          Note: Tested and it worked fine

          I had no idea how it would work. But I tried it after all simpler suggestions failed. and it worked perfectly! Many thanks.

          (1) This seems like a case where -exec … <> + would work. (2a) What’s the point of awk ‘‘ ? (2b) It ( awk ‘‘ ) breaks filenames that contain whitespace. (3) Why strip off ./ ? rm ./file-1.php works just fine, but rm $1 breaks if the filename begins with a . (4) Why specify the -r option to rm when you’re passing it only the names of plain files, never directories? (5) Why say «rm -rvf» » » when you could say simply «rm -rvf » ? … (Cont’d)

          Источник

          how to delete files have specific pattern in linux?

          Are there any other images in this directory that should not be deleted and if so what are their names?

          Test with ls -al [[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]-image-[[:digit:]]* if that matches what you want to delete, then rm [[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]-image-[[:digit:]]*

          3 Answers 3

          Ok I solve it with this pattern

          it matches all the file names start with 12345-image- then a number then — symbol and any thing after that

          as I found it’s globbing in bash not regex and I found this app really use full

          That will match a whole lot more than you think, but only if the filenames start with 12345 . From your comment of «I have just tested this regex 1234-image-. » you indicated that the number of digits was not fixed at five — it this a requirement?.

          as I tested it worked. I just want to select files start with specific id then have -image- then a number and an extension at the end

          for pic in 12345*.;do rm $pic;done 

          for more information on wildcards take a look here

          So long as you do NOT have filenames with embedded ‘\n’ character, then the following find and grep will do:

          find . -type f | grep '^.*/[[:digit:]]\-image-[[:digit:]]\' 

          It will find all files below the current directory and match (1 to 5 digits) followed by «-image-» followed by another (1 to 5 digits). In your case with the following files:

          $ ls -1 123-image-99999-small.jpg 12345-image-1-medium.jpg 12345-image-2-medium.png 12345-image-3-large.jpg 12345-image-profile-large.png 12345-image-profile-medium.jpg 12345-image-profile-small.jpg 

          The files you request are matched in addition to 123-image-99999-small.jpg , e.g.

          $ find . -type f | grep '^.*/[[:digit:]]\-image-[[:digit:]]\' ./123-image-99999-small.jpg ./12345-image-3-large.jpg ./12345-image-2-medium.png ./12345-image-1-medium.jpg 

          You can use the above in a command substitution to remove the files, e.g.

          $ rm $(find . -type f | grep '^.*/[[:digit:]]\-image-[[:digit:]]\') 
          $ l1 12345-image-profile-large.png 12345-image-profile-medium.jpg 12345-image-profile-small.jpg 

          If Your find Supports -regextype

          If your find supports the regextype allowing you to specify which set of regular expression syntax to use, you can use -regextype grep for grep syntax and use something similar to the above to remove the files with the -execdir option, e.g.

          $ find . -type f -regextype grep -regex '^.*/[[:digit:]]\+-image-[[:digit:]]\+.*$' -execdir rm '<>' + 

          I do not know whether this is supported by BSD or Solaris, etc. so check before turning it loose in a script. Also note, [[:digit:]]\+ tests for (1 or more) digits and is not limited to 5-digits as shown in your question.

          Источник

Оцените статью
Adblock
detector