2

I used the find command to find several files and folders and output them to a text file like so:

nohup find /oradba -name '*soapr*' 2>/dev/null >find_soapr_db40.txt &

So instead of displaying my results to the screen, I sent them to the file. Normally, I could just append "-exec rm -rf {} \;" to the end of my find command to find related files and delete them at the same time.

find / -name '*soatst*' 2>/dev/null -exec rm -rf {} \;

But how can I run a command to process each line from the .txt file and delete the files they are referencing from the disk?

The text file contains items like the following:

/oradba/app/oracle/admin/soaprod2
/oradba/app/oracle/admin/soaprd2
/oradba/app/oracle/product/10.2.0.5/db_aprpsu/dbs/initsoaprd2.ora
/oradba/app/oracle/product/10.2.0.5/db_aprpsu/dbs/hc_soaprd2.dat
/oradba/app/oracle/product/10.2.0.5/db_aprpsu/dbs/alert_soaprd2.log
/oradba/app/oracle/product/10.2.0.5/db_aprpsu/dbs/spfilesoaprd2.ora
2

Danger: it is perfectly legal for Unix paths to contain newlines. If any of your paths contain newlines, this is potentially dangerous. Consider using \0 to separate the filenames instead by using GNU find's -print0 option, and then processing them using GNU xargs' -0 option.


You can use the following:

files=()

while IFS= read -r file; do
    files+=( "$file" )
done < ind_soapr_db40.txt

rm -r -- "${files[@]}"

You could call rm each time directly in the for loop, but that would be slower than populating the list of files and processing them in one invocation of rm.

If you have bash4+, you can instead use mapfile:

mapfile -t files < ind_soapr_db40.txt
rm -r -- "${files[@]}"
0

This Perl one-liner should work even if your file names have newlines:

perl -000ne 'unlink (/(.+?\/[^\/]+)\n/sg);' list 

To recursively delete directories and their contents, try this:

perl -000ne 'use File::Path; rmtree (/(.+?\/[^\/]+)\n/sg);' list 

Explanation

  • -000 : activate paragraph mode, reads the entire file at once.
  • -ne : read the file given as an argument (-n) and run the script passed by -e.

  • /(.+?\/[^\/]+)\n/sg : look for any character, followed by a /, then as many non-/ characters as possible (including newlines thanks to the s modifier) until the next newline. Since file names cannot contain /, this should select the whole path and separate ea

  • Pass the matches (file names) returned by the regular expression above to unlink() to delete them.

  • I like this solution! It seems to work really well, but how do I get it to remove directories recursively? Your suggestion is only removing matching files. – etho201 Jan 18 '14 at 5:41
  • @user2554129 see updated answer for a version that deletes directories. However, unless your file names actually do contain new lines (which is possible but not very likely), use \@ChrisDown's answer which is the classic *nix way. – terdon Jan 18 '14 at 13:47

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.