Grep and delete file - linux

I run the following code to delete malware, I would like to extend it with a pipe so it can delete the files that found to contain the string below (delete result return by grep).
grep -rnw . -e "ALREADY_RUN_1bc29b36f342a82aaf6658785356718"
It return a list of files
./gallery.php:2:if (!defined('ALREADY_RUN_1bc29b36f342a82aaf6658785356718'))
./gallery.php:4:define('ALREADY_RUN_1bc29b36f342a82aaf6658785356718', 1);
./wp-includes/SimplePie/HTTP/db.php:2:if (!defined('ALREADY_RUN_1bc29b36f342a82aaf6658785356718'))
./wp-includes/SimplePie/HTTP/db.php:4:define('ALREADY_RUN_1bc29b36f342a82aaf6658785356718', 1);
./wp-includes/SimplePie/Parse/template.php:2:if (!defined('ALREADY_RUN_1bc29b36f342a82aaf6658785356718'))
./wp-includes/SimplePie/Parse/template.php:4:define('ALREADY_RUN_1bc29b36f342a82aaf6658785356718', 1);
./wp-includes/SimplePie/XML/file.php:2:if (!defined('ALREADY_RUN_1bc29b36f342a82aaf6658785356718'))

Here's a solution using xargs to process files as they are listed from stdin.
Grep recursively searches the contents of . for the pattern (you don't seem to be using any regex features, so I changed the flag to -F for fixed string).
Here's a simple script that will delete the files, note that it will split on all newlines, including newlines in file names.
$ grep -rl -F "ALREADY_RUN_1bc29b36f342a82aaf6658785356718" . | \
xargs -I'{}' rm '{}'
For the sake of completeness, here's a command that will work regardless of file name (using rm is safe because we know the path MUST begin with ./)
$ find . -type f -exec \
/bin/sh -c 'grep -q -F "$0" "$1" && rm "$1"' 'ALREADY_RUN_1bc29b36f342a82aaf6658785356718' '{}' \;
and deleting multiple files at once.
$ find . -type f -exec \
/bin/sh -c 'grep -q -F "$0" "$#" && rm "$#"' 'ALREADY_RUN_1bc29b36f342a82aaf6658785356718' '{}' +

Related

Delete files with less than x characters in a directory

I am trying to write a bash script which is given a directory as a parameter and removes all files with less than 4 characters. My script is currently as follows:
#!/bin/bash
cd $1
rm ???
rm ??
rm ?
This method works but it throws an error whenever a file without <4 characters is present. For example, if there was no 2 character filename in the given directory, an error would be presented where "rm cannot remove any character '??'". I was wondering how I make my bash script so that there is no error like that thrown without using loops or conditionals.
You may use rm -f. From man rm:
-f, --force
ignore nonexistent files and arguments, never prompt
To protect against files named literally -- or -f, use a leading --.
rm -f -- ? ?? ???
But that -f - it looks dangerous (as if rm in a script is not dangorous enough). Really a better option is not to use globbing and use find:
find "$1" -maxdepth 1 -type f '(' -name '?' -o -name '??' -o -name '???' ')' -exec rm {} +
Enable the nullglob option so globs that don't match any files are removed.
#!/bin/bash
shopt -s nullglob
cd "$1"
rm ? ?? ???
Note that you will now get an error if there are no matching files at all:
rm: missing operand
Try 'rm --help' for more information.
You can redirect the stderr to /dev/null:
rm ??? 2>/dev/null
rm ?? 2>/dev/null
rm ? 2>/dev/null
"removes all files with less than 4 characters" and "without using loops or conditionals" you can use:
find all files with the length of the filename between 1 and 4 chars:
find . -type f -exec basename '{}' ';' | egrep '^.{1,3}$' where you can replace . with the desired directory as argument.
And afterwards you can rm -f $(find . -type f -exec basename '{}' ';' | egrep '^.{1,3}$)'

Remove all files contain specific string - Bash

I have these bad data
AWS-Console.pngcrop-AWS-Console.png
Alimofire.pngcrop-Alimofire.png
Amazon-ECR-.pngcrop-Amazon-ECR-.png
Amazon-ECS.pngcrop-Amazon-ECS.png
Amazon-RDS.pngcrop-Amazon-RDS.png
Angular.pngcrop-Angular.png
AngularJS.pngcrop-AngularJS.png
.... 1000 more
I'm trying to delete them
I've tried
ls public/assets/fe/img/skill/ | grep crop | rm -rf *crop*
ls public/assets/fe/img/skill/ | grep crop | rm -rf
rm -rf $(ls public/assets/fe/img/skill/ | grep crop)
None of them work ...
rm can handle the glob expressions that ls handles:
rm public/assets/fe/img/skill/*crop*
Use the find command instead
find . -name "*crop*" -type f -exec rm -i {} \;
-type f will specify to search file only and avoid directories
-exec requires the command input to end with \;, the {} being substitute by the result of the command
the -i will ask you to confirm ; remove it once sure what you do.
advice display the result beforehand with -print in place of -exec ...
find . -name "*crop*" -type f -print
More here where your question would find more accurate answers
The main problem in your commands is the missing path in the output of the ls command.
ls public/assets/fe/img/skill/ | grep crop will retur e.g. AWS-Console.pngcrop-AWS-Console.png which is passed to rm. But rm AWS-Console.pngcrop-AWS-Console.png fails because there is no such file in the current directory. It should be rm public/assets/fe/img/skill/AWS-Console.pngcrop-AWS-Console.png instead.
Adding -d to the ls command should do the trick:
ls -d public/assets/fe/img/skill/ | grep crop | rm -rf
rm -rf $(ls -d public/assets/fe/img/skill/ | grep crop)
As pointed out in other answers, other solutions exist, including:
rm public/assets/fe/img/skill/*crop*
find public/assets/fe/img/skill/ -name "*crop*" -type f -exec rm -i {} \;
If it's a really large number of files (apparently wasn't in your case), xargs can speed up the process. This applies for a lot of things you might want to read from a pipe.
find . -name "*crop*" -type f | xargs rm
The main advantage of using find here is that it's an easy way to ignore directories. If that's not an issue, let the OS handle all that.
printf "%s\n" public/assets/fe/img/skill/*crop* | xargs rm
If you need to be able to pick up files in subdirectories -
shopt -s globstar # double asterisks not include arbitrary preceding paths
printf "%s\n" public/assets/fe/img/skill/**crop* | xargs rm
You might want to look over the list first, though.
printf "%s\n" public/assets/fe/img/skill/*crop* >crop.lst
# check the list - vi, grep, whatever satisfies you.
xargs rm < crop.lst # fast-delete them in bulk

Bash script: Using grep to find a string that is also an option

I call the program with the text I want to find, so programname '-r'
Then, within the script I have text="${1}"
find . -r -name "hi.*" -exec grep -l "${text}" {} \;
The second half of that simplifies to grep -l -r and it waits for another input
How do I specify that -r is the string to be found, and not an option?
The POSIX standard mandates that grep support an option -e that forces the following argument to be treated as a regular expression, rather than another option.
find . -r -name "hi.*" -exec grep -l -e "$text" {} \;
Add -- after the -l [or your last valid option]. That stops option processing in grep so that your text will be interpreted as a string to search for and not an option:
find . -r -name "hi.*" -exec grep -l -- "${text}" {} \;

Delete files with string found in file - Linux cli

I am trying to delete erroneous emails based on finding the email address in the file via Linux CLI.
I can get the files with
find . | xargs grep -l email#example.com
But I cannot figure out how to delete them from there as the following code doesn't work.
rm -f | xargs find . | xargs grep -l email#example.com
Solution for your command:
grep -l email#example.com * | xargs rm
Or
for file in $(grep -l email#example.com *); do
rm -i $file;
# ^ prompt for delete
done
For safety I normally pipe the output from find to something like awk and create a batch file with each line being "rm filename"
That way you can check it before actually running it and manually fix any odd edge cases that are difficult to do with a regex
find . | xargs grep -l email#example.com | awk '{print "rm "$1}' > doit.sh
vi doit.sh // check for murphy and his law
source doit.sh
You can use find's -exec and -delete, it will only delete the file if the grep command succeeds. Using grep -q so it wouldn't print anything, you can replace the -q with -l to see which files had the string in them.
find . -exec grep -q 'email#example.com' '{}' \; -delete
I liked Martin Beckett's solution but found that file names with spaces could trip it up (like who uses spaces in file names, pfft :D). Also I wanted to review what was matched so I move the matched files to a local folder instead of just deleting them with the 'rm' command:
# Make a folder in the current directory to put the matched files
$ mkdir -p './matched-files'
# Create a script to move files that match the grep
# NOTE: Remove "-name '*.txt'" to allow all file extensions to be searched.
# NOTE: Edit the grep argument 'something' to what you want to search for.
$ find . -name '*.txt' -print0 | xargs -0 grep -al 'something' | awk -F '\n' '{ print "mv \""$0"\" ./matched-files" }' > doit.sh
Or because its possible (in Linux, idk about other OS's) to have newlines in a file name you can use this longer, untested if works better (who puts newlines in filenames? pfft :D), version:
$ find . -name '*.txt' -print0 | xargs -0 grep -alZ 'something' | awk -F '\0' '{ for (x=1; x<NF; x++) print "mv \""$x"\" ./matched-files" }' > doit.sh
# Evaluate the file following the 'source' command as a list of commands executed in the current context:
$ source doit.sh
NOTE: I had issues where grep could not match inside files that had utf-16 encoding.
See here for a workaround. In case that website disappears what you do is use grep's -a flag which makes grep treat files as text and use a regex pattern that matches any first-byte in each extended character. For example to match Entité do this:
grep -a 'Entit.e'
and if that doesn't work then try this:
grep -a 'E.n.t.i.t.e'
Despite Martin's safe answer, if you've got certainty of what you want to delete, such as in writing a script, I've used this with greater success than any other one-liner suggested before around here:
$ find . | grep -l email#example.com | xargs -I {} rm -rf {}
But I rather find by name:
$ find . -iname *something* | xargs -I {} echo {}
rm -f `find . | xargs grep -li email#example.com`
does the job better. Use `...` to run the command to offer the file names containing email.#example.com (grep -l lists them, -i ignores case) to remove them with rm (-f forcibly / -i interactively).
find . | xargs grep -l email#example.com
how to remove:
rm -f 'find . | xargs grep -l email#example.com'
Quick and efficent. Replace find_files_having_this_text with the text you want to search.
grep -Ril 'find_files_having_this_text' . | xargs rm

Use grep to find content in files and move them if they match

I'm using grep to generate a list of files I need to move:
grep -L -r 'Subject: \[SPAM\]' .
How can I pass this list to the mv command and move the files somewhere else?
If you want to find and move files that do not match your pattern (move files that don't contain 'Subject \[SPAM\]' in this example) use:
grep -L -Z -r 'Subject: \[SPAM\]' . | xargs -0 -I{} mv {} DIR
The -Z means output with zeros (\0) after the filenames (so spaces are not used as delimeters).
xargs -0
means interpret \0 to be delimiters.
The -L means find files that do not match the pattern. Replace -L with -l if you want to move files that match your pattern.
Then
-I{} mv {} DIR
means replace {} with the filenames, so you get mv filenames DIR.
This alternative works where xargs is not availabe:
grep -L -r 'Subject: \[SPAM\]' . | while read f; do mv "$f" out; done
This is what I use in Fedora Core 12:
grep -l 'Subject: \[SPAM\]' | xargs -I '{}' mv '{}' DIR
This is what helped me:
grep -lir 'spam' ./ | xargs mv -t ../spam
Of course, I was already in required folder (that's why ./) and moved them to neighboring folder. But you can change them to any paths.
I don't know why accepted answer didn't work. Also I didn't have spaces and special characters in filenames - maybe this will not work.
Stolen here: Grep command to find files containing text string and move them
mv `grep -L -r 'Subject: \[SPAM\]' .` <directory_path>
Assuming that the grep you wrote returns the files paths you're expecting.
Maybe this will work:
mv $(grep -l 'Subject: \[SPAM\]' | awk -F ':' '{print $1}') your_file
There are several ways but here is a slow but failsafe one :
IFS=$'\n'; # set the field separator to line break
for $mail in $(grep -L -r 'Subject: \[SPAM\]' .); do mv "$mail" your_dir; done;
IFS=' '; # restore FS
Work perfect fo me :
move files who contain the text withe the word MYSTRINGTOSEARCH to directory MYDIR.
find . -type f -exec grep -il 'MYSTRINGTOSEARCH' {} \; -exec mv {} MYDIR/ \;
I hope this helps
You can pass the result to the next command by using
grep ... | xargs mv {} destination
Check man xargs for more info.

Resources