Trying to script deleting files from wildcards in a text file

I'm trying to script deleting files whose filenames match wildcards in a text file.

I'm using the following

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"

in the file list there are lines

file*
test*

I get the following if i run this

rm: cannot remove ‘file*’: No such file or directory
rm: cannot remove ‘test*’: No such file or directory

I think the * isn't accepted to delete files such as

file 1
file2
file2.txt
test 001 more teskt.txt

Sorry I'm no linux expert. Maybe someone has an easy answer, maybe replace the * with something?


Solution 1:

Pathname expansion happens after variable expansion, but only on unquoted parts of the command line.

rm -- $line  # <- no double quotes to expand wildcards

This wouldn't work for filenames containing spaces, as word splitting also happens after variable expansion.

You can use Perl to expand globs:

perl -lne 'unlink glob' -- list.txt

Normal glob needs whitespace backslashed, but you can switch to File::Glob for a different behaviour if it's more convenient to you:

perl -MFile::Glob=:bsd_glob -lne 'unlink glob' -- list.txt

Solution 2:

Find

If you're only deleting files in the pwd (like in the question), you can replace rm with find -name like this:

find . -maxdepth 1 -name "$line"

This just outputs filenames that match the glob. If the output looks good, add -delete at the end.


Python

For anything not covered by the find solution above, this should work:

python3 -c 'import glob, os, sys; [print(f) for f in glob.glob(sys.argv[1])]' "$line"

If the output looks good, replace print with os.remove.

Or you could write the whole script in Python:

#!/usr/bin/env python3
'''
For each line from "fileinput", treat it as a glob and delete
the matching files.
'''

import fileinput
import glob
import os

for line in fileinput.input():
    line = line.rstrip('\n')
    for file in glob.glob(line):
        # If the output looks good, replace "print" with "os.remove"
        print(file)

Though note that if no arguments are given, fileinput reads from stdin instead of erroring.