web-dev-qa-db-fra.com

supprimer le fichier mais exclure tous les fichiers d'une liste

Je dois nettoyer un dossier régulièrement. Je reçois une liste de fichiers qui contient du texte, quels fichiers sont autorisés. Maintenant, je dois supprimer tous les fichiers qui ne sont pas dans ce fichier.

Exemple:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

Mon dossier do clean-up contient ceci à titre d'exemple:

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Donc, ces fichiers doivent être supprimés:

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Je recherche quelque chose pour créer une commande de suppression avec une option pour exclure certains fichiers fournis par fichier.

15
stefan83

La commande rm est commentée afin que vous puissiez vérifier et vérifier qu’elle fonctionne correctement. Puis, commentez simplement cette ligne.

La section check directory vous évitera d’exécuter accidentellement le script à partir du mauvais répertoire et d’obstruer les mauvais fichiers.

Vous pouvez supprimer la ligne echo deleting pour qu'elle s'exécute en mode silencieux.

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done
8
L. D. James

Ce script python peut faire ceci:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

Une partie importante est de ne pas commenter la fonction os.unlink().

NOTE: ajoutez ce script et dont-delete.txt à votre dont-delete.txt pour qu'ils soient tous les deux dans la liste et conservez-les dans le même répertoire.

10
Sergiy Kolodyazhnyy

Voici un one-liner:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls imprime tous les fichiers du répertoire en cours (par ordre de tri)
  2. sort dont_delete imprime tous les fichiers que nous ne voulons pas supprimer par ordre de tri
  3. l'opérateur <() transforme une chaîne en objet de type fichier
  4. Les commandes comm comparent deux fichiers préalablement triés et impriment des lignes sur lesquelles ils diffèrent.
  5. l'utilisation des indicateurs -2 -3 force comm à n'imprimer que les lignes contenues dans le premier fichier mais pas le second, ce qui correspond à la liste des fichiers pouvant être supprimés en toute sécurité.
  6. l'appel tail +2 consiste simplement à supprimer l'en-tête de la sortie comm, qui contient le nom du fichier d'entrée
  7. Nous avons maintenant une liste de fichiers à supprimer en sortie standard. Nous dirigeons cette sortie vers xargs qui transformera le flux de sortie en une liste d’arguments pour rm. L'option -p force xargs à demander une confirmation avant l'exécution.
3
gardenhead

FWIW, il semblerait que vous puissiez le faire de manière native dans zshname__, en utilisant le qualificatif (+cmd) glob.

Pour illustrer, commençons par quelques fichiers

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

et un fichier de liste blanche

 % cat keepfiles.txt
foo
kazoo
bar

Commencez par lire la liste blanche dans un tableau:

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

ou peut-être mieux

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(équivalent de la commande mapfilede bash - ou de son synonyme readarrayname__). Maintenant, nous pouvons vérifier si une clé (nom de fichier) existe dans le tableau en utilisant ${keepfiles[(I)filename]} qui renvoie 0 si aucune correspondance n'est trouvée:

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

Nous pouvons utiliser ceci pour créer une fonction qui retourne trues'il n'y a pas de correspondance pour $REPLY dans le tableau:

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

Enfin, nous utilisons cette fonction comme qualificatif dans notre commande:

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

ou, dans votre cas

 % rm -- *(+nokeep)

(Vous voudrez probablement ajouter le nom du fichier de liste blanche à la liste blanche.)

1
steeldriver

En supposant qu’il n’y ait pas d’espace (Espaces/Onglets) dans la liste de vos fichiers dans un fichier nommé listname__, vous feriez alors:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \)

Ajoutez simplement -delete à la commande ci-dessus pour supprimer les fichiers qui n'existent pas dans le fichier liste . Si votre recherche n'a pas l'option -delete, vous pouvez utiliser rmavec -exec comme suit:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} \;

Ou tilisez -exec avec + terminator à la place.

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} +

echoest simplement utilisé pour une exécution à sec.

0
αғsнιη

En supposant que votre shell bash ait le extglobshopt activé, voici une alternative un peu plus conservatrice:

rm !($(tr \\n \| < keep.txt))

(... accompagnant sinon excellente suggestion de communication de @ gardenhead!)

0
conny