26

I have a text file that has a list of paths to various files. Is there a command I can use that will iterate through each line and delete the file at the stated path?

olfek
  • 1,305

6 Answers6

36

Use xargs:

xargs rm < file  # or
xargs -a file rm

But that will not work if the file names/paths contain characters that should be escaped.

If your filenames don't have newlines, you can do:

tr '\n' '\0' < file | xargs -0 rm # or
xargs -a file -I{} rm {}

Alternatively, you can create the following script:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "Usage: $(basename $0) FILE\n"
    exit 1
fi

if [ ! -e "$1" ]; then
    echo -e "$1: File doesn't exist.\n"
    exit 1
fi

while read -r line; do
    [ -n "$line" ] && rm -- "$line"
done < "$1"

Save it as /usr/local/bin/delete-from, grant it execution permission:

sudo chmod +x /usr/local/bin/delete-from

Then run it with:

delete-from /path/to/file/with/list/of/files
oerdnj
  • 7,940
Eric Carvalho
  • 54,385
  • 2
    Really clean answer, but cat is not required, you can use stdin redirection: < file xargs rm – kos Mar 13 '15 at 21:12
  • Its splitting names of folders up and then looking for them. E.g. MY FOLDER is being interpreted as "MY" and "FOLDER"? – olfek Mar 13 '15 at 21:25
  • @sudoman Answer updated. – Eric Carvalho Mar 13 '15 at 23:42
  • If the files don't have spaces then you could just "rm -- $(cat file)" in bash or "rm -- cat file" in (ba)sh or csh. – shooper Mar 14 '15 at 02:02
  • @shooper cat is unuseful, as just stated, take advantage from stdin! Look at his updated answer – kos Mar 14 '15 at 03:55
  • In the comment I made, the "cat" is useful kos, as it reads the file onto the command line, so that if you have a list of files in a file the $(cat file) expands to the contents of file and rm picks those up as arguments. Try it (probably without rm). – shooper Mar 14 '15 at 04:02
  • @shooper In the comment you made cat is required in order to make it work, but the point is there's no reason to invoke a subshell for doing that! – kos Mar 14 '15 at 04:12
  • @shooper I never said that it wouldn't work, i said that it would be overcomplicated – kos Mar 14 '15 at 04:14
  • You can also handle "whitespace but not newlines" in the filenames with xargs -d '\n' rm < file – glenn jackman May 04 '16 at 12:41
23

Here's one way that can deal with file names with whitespace, backslashes and other strange characters:

while read -r file; do rm -- "$file"; done < list.txt

That will read each line of list.txt, save it as $file and run rm on it. The -r ensures that backslashes are read literally (so that \t matches a \ and a t and not a TAB). The -- ensures that it also deals with file names starting with -.

You could also do this in Perl:

perl -lne '$k{$_}++; END{unlink for keys(%k)}' list.txt

This one wil read each file name into the %k hash and then use unlink to delete each of them.

terdon
  • 100,812
10

Through python.

import sys
import os
fil = sys.argv[1]
with open(fil) as f:
    for line in f:
        os.remove(line.rstrip('\n'))

Save the above script in a file named like script.py and then execute the script by firing the below command on terminal.

python3 script.py file

file is an input file where the path of the files you actually want to remove are stored.

Avinash Raj
  • 78,556
4

Silly, but here is one:

 tar -cvf /dev/null --remove-files -T filename
shooper
  • 141
3

Another way to do this:

You can 'prepare' the file by making it a shell script:

$ sed -E "s/^(.*)$/rm '\1'/" input_file
rm 'file1'
rm 'file2'
rm 'file with some spaces.ext'

If your filenames may have a single quote ('), you can use this slightly expanded version to escape them first:

$ sed -E "s/'/'\\\''; s/^(.*)$/rm '\1'/" input_file
rm 'file1'
rm 'file2'
rm 'file with some spaces.ext'
rm 'a file with "quotes"'
rm 'a file with '\''quotes'\'''

And you can run this by piping it to sh:

$ sed -E "s/'/'\\\''; s/^(.*)$/rm '\1'/" input_file | sh
terdon
  • 100,812
Martin Tournoij
  • 253
  • 1
  • 13
2

As I understand it, you have a text file with the files with the complete paths. There are two possibilities:

  1. Your list has the filenames separated by newlines, i.e. each line has the complete path to a file. in this case: here is a simple way out:

    for i in $(cat listOfFiles.txt); do
        rm -f $i
    done
    
  2. If your list has one or more lines of filenames separated by spaces or tabs, then here is the drill:

    sed -i 's/\s\+/\n/g' listOfFiles.txt
    

    this will convert all whitespaces to newlines

    for i in $(cat listOfFiles.txt); do
        rm -f $i
    done
    

Yes, there are many ways to get it done, but this is a very simple approach.

pomsky
  • 68,507