Delete files listed in a file (bash question?)

2 réponses [Dernière contribution]
Avron

I am a translator!

Hors ligne
A rejoint: 08/18/2020

I'd like to delete files listed in a file, each line has a single file name, all files are in the same directory and they are listed with filename only. The file names can include *any character*, including characters not in the current locale. What would be a safe way to do that?

I found things like:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

However, looking at https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html, it seems that the shell might still do special things for $ ` \ and !. Would single quotes around $file be better? What if the file name has single quotes?

I am also thinking that I could search for $ ` \ and ! in the file list first, exclude files that would have that in the name (hopefully, not that many, then I would handle them manually one by one) and the run the above. Would that work?

Magic Banana

I am a member!

I am a translator!

Hors ligne
A rejoint: 07/24/2010

However, looking at https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html, it seems that the shell might still do special things for $ ` \ and !.

I am pretty sure (and quick tests confirm it) there is no problem with the code you found: $ is not recursively evaluated.

Would single quotes around $file be better?

No, they would not. That would be asking to repetitively (as many times as there are lines in delete.list) remove a file that is literally named '$file', without the single quotes.

I could search for $ ` \ and ! in the file list

If you want to do that anyway:
$ grep '[$`*\!]' delete.list

WizardHemp
Hors ligne
A rejoint: 11/28/2021

If you want to be extremely cautious, You need delete.list to delimited by null bytes instead of newlines because unix filenames can have newlines in them. And then you would want to have IFS=$'\0' instead of IFS= , many of the GNU utilities have options to let them delimit by null bytes instead of newlines (If you are able to regenerate delete.list).

But if you assume that no filenames have newline characters in their name then what you did works because the expansion characters are not recursively evaluated. The thing inside of "" is only evaluated once. So "$file" turns into 'filename', where filename is the value of $file

you could also do

xargs -a delete.list -d '\n' rm --

for newline delimited or

xargs -a delete.list -0 rm --

for null delimited