Unix: come eliminare i file elencati in un file


92

Ho un lungo file di testo con un elenco di maschere di file che desidero eliminare

Esempio:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

Ho bisogno di eliminarli. Ho provato rm `cat 1.txt` e dice che l'elenco è troppo lungo.

Ho trovato questo comando, ma quando controllo le cartelle dall'elenco, alcune di esse hanno ancora file. xargs rm <1.txtLa chiamata manuale rm rimuove i file da tali cartelle, quindi nessun problema con le autorizzazioni.


8
Anche se sono passati sei anni: ti dispiacerebbe accettare una delle risposte? Ciò contrassegnerà la domanda come risolta e aiuterà anche altri utenti.
MERose

Risposte:


114

Questo non è molto efficiente, ma funzionerà se hai bisogno di schemi glob (come in / var / www / *)

for f in $(cat 1.txt) ; do 
  rm "$f"
done

Se non hai alcun pattern e sei sicuro che i tuoi percorsi nel file non contengano spazi bianchi o altre cose strane, puoi usare xargs in questo modo:

xargs rm < 1.txt

4
Cosa succederà con la prima soluzione (utilizzando CAT) se il percorso contiene uno spazio?
a.dibacco

58

Supponendo che l'elenco dei file sia nel file 1.txt, quindi eseguire:

xargs rm -r <1.txt

L' -ropzione causa la ricorsione in qualsiasi directory denominata in 1.txt.

Se alcuni file sono di sola lettura, utilizza l' -fopzione per forzare l'eliminazione:

xargs rm -rf <1.txt

Sii cauto con l'input a qualsiasi strumento che esegue eliminazioni programmatiche. Fare certi che i file denominati nel file di input sono davvero da eliminare. Prestare particolare attenzione agli errori di battitura apparentemente semplici. Ad esempio, se inserisci uno spazio tra un file e il suo suffisso, appariranno due nomi di file separati:

file .txt

è in realtà due file separati: filee .txt.

Potrebbe non sembrare così pericoloso, ma se l'errore di battitura è qualcosa del genere:

myoldfiles *

Poi invece di eliminare tutti i file che iniziano con myoldfiles, si finirà per l'eliminazione myoldfilese tutti i non-dot-file e le directory nella directory corrente. Probabilmente non quello che volevi.


1
"myoldfiles /" o "/ tmp" ancora più disastroso con -rf. Notare il carattere spazio accanto a "/".
Ray

23

Usa questo:

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

Se hai bisogno di espansione glob puoi omettere le virgolette $file:

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

Ma tieni presente che i nomi dei file possono contenere contenuti "problematici" e utilizzerei la versione non quotata. Immagina questo modello nel file

*
*/*
*/*/*

Questo eliminerebbe parecchio dalla directory corrente! Ti incoraggio a preparare l'elenco di eliminazione in modo che i pattern glob non siano più necessari e quindi a utilizzare le virgolette come nel mio primo esempio.


3
Questo è attualmente l'unica risposta che gestisce tutti /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashese come bonus è POSIX e funziona su GNU / Linux, MacOS e BSD.
quell'altro ragazzo il

17

È possibile utilizzare "\ n" per definire il nuovo carattere di riga come delimitatore.

xargs -d '\n' rm < 1.txt

Fai attenzione con -rf perché può eliminare ciò che non vuoi se 1.txt contiene percorsi con spazi. Ecco perché il nuovo delimitatore di riga è un po 'più sicuro.

Sui sistemi BSD, è possibile utilizzare l'opzione -0 per utilizzare i nuovi caratteri di riga come delimitatori in questo modo:

xargs -0 rm < 1.txt

1
Su OS X questo mi faxargs: illegal option -- d
waldyrious

Buon punto. Sembra che non ci sia altra opzione che -0su OS X.
Ray

2
xargs -I_ rm _funziona anche in OS X :) vedere stackoverflow.com/a/39335402/266309
waldyrious

Se usi BSD xargs (dove non c'è -d), puoi prima convertire le nuove righe in null:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog

13

Puoi usare questo one-liner:

cat 1.txt | xargs echo rm | sh

Che fa l'espansione della shell ma viene eseguito rmil numero minimo di volte.


Finché un'espansione non è troppo lunga?
Douglas Leeder

1
È vero, un glob potrebbe produrre un elenco di argomenti troppo lungo: puoi aggiungere l' -n <n>argomento a xargsper ridurre il numero di argomenti passati a ciascun rm, ma ciò non ti proteggerà da un singolo glob che supera il limite.
tgdavies

13

xargs -I{} sh -c 'rm {}' < 1.txtdovrebbe fare quello che vuoi. Fai attenzione con questo comando poiché una voce errata in quel file potrebbe causare molti problemi.

Questa risposta è stata modificata dopo che @tdavies ha sottolineato che l'originale non eseguiva l'espansione della shell.


Grazie, ma non c'è bisogno di eliminare cartelle, solo file
Alexander

2
I glob non verranno espansi, poiché non vengono mai "visti" dalla shell.
tgdavies

@tdavies wow - hai ragione. Questo comando (anche se un po 'più brutto) funzionerà:xargs -I{} sh -c 'rm {}' < 1.txt
Mark Drago

4

In questo caso particolare, a causa dei pericoli citati in altre risposte, lo farei

  1. Modifica in es. Vim e :%s/\s/\\\0/g, facendo l'escape di tutti i caratteri spazio con una barra rovesciata.

  2. Quindi :%s/^/rm -rf /, anteponendo il comando. Con -rnon devi preoccuparti di avere directory elencate dopo i file in esse contenuti, e con -fesso non si lamenterà a causa di file mancanti o voci duplicate.

  3. Esegui tutti i comandi: $ source 1.txt


Gli spazi non sono gli unici caratteri che necessitano di escape, popolari nei nomi di file sono anche parentesi di qualsiasi tipo che possono portare a un'espansione indesiderata.
emk2203

4

cat 1.txt | xargs rm -f | bash Eseguire il comando eseguirà le seguenti operazioni solo per i file.

cat 1.txt | xargs rm -rf | bash Eseguire il comando eseguirà il seguente comportamento ricorsivo.


2

Solo per fornire un altro modo, puoi anche usare semplicemente il seguente comando

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )

1

Ecco un altro esempio di loop. Questo contiene anche un 'istruzione if' come esempio di controllo per vedere se la voce è un 'file' (o una 'directory' per esempio):

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done

0

Qui è possibile utilizzare set di cartelle da deletelist.txt mentre evitando alcuni modelli pure

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end

0

Ciò consentirà ai nomi dei file di avere spazi (esempio riproducibile).

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh

0

Nel caso in cui qualcuno preferisca sede rimuova senza l'espansione del carattere jolly :

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

Promemoria: utilizza nomi di percorso assoluti nel file o assicurati di essere nella directory corretta.

E per completezza lo stesso con awk:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

L'espansione con caratteri jolly funzionerà se le virgolette singole vengono rimosse, ma ciò è pericoloso nel caso in cui il nome del file contenga spazi. Ciò avrebbe bisogno di aggiungere virgolette attorno ai caratteri jolly.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.