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

17

J'ai besoin de nettoyer un dossier périodiquement. 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 de nettoyage contient ceci comme 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.

stefan83
la source
Est-ce un devoir?
mook765
J'espère que tu n'es pas son professeur. lol
Gujarat Santana
2
@gujarat Nous ne sommes pas un service de devoirs gratuit, donc le commentaire est justifié. Quant à la question elle-même, elle peut être utile à d'autres, elle est donc ouverte jusqu'à présent.
Sergiy Kolodyazhnyy
@Serg Je suis totalement d'accord avec vous
Gujarat Santana

Réponses:

9

La rmcommande est mise en commentaire afin que vous puissiez vérifier et vérifier qu'elle fonctionne selon les besoins. Décompressez ensuite cette ligne.

La check directorysection s'assurera que vous n'exécutez pas accidentellement le script à partir du mauvais répertoire et que vous clobez les mauvais fichiers.

Vous pouvez supprimer la echo deletingligne 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
LD James
la source
J'ai édité votre code pour éviter une utilisation inutilels et la capture inutile de la sortie degrep si tout ce que vous voulez savoir est s'il y a une correspondance ou non. J'ai également utilisé des modèles de chaînes fixes pour éviter les problèmes d'échappement.
David Foerster
@DavidFoerster Merci pour la contribution. Cependant, lorsque vous avez changé la whileboucle en forboucle, vous avez par inadvertance changé le iteration keyde ien f. dans la déclaration, qui a brisé le code. Je l'ai corrigé.
LD James
Oups, force d'habitude. J'ai tendance à abréger les noms de variables shell pour les noms de fichiers commef . ;-P (… et +1 pour votre réponse que j'ai oubliée plus tôt.)
David Foerster
10

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)

La partie importante est de décommenter la os.unlink()fonction.

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

Sergiy Kolodyazhnyy
la source
1
J'ai changé votre code pour utiliser une recherche setau lieu d'une liste pour O (1) au lieu de la recherche O (n) dans la deuxième partie.
David Foerster
merci pour votre aide, je suis normalement un gars de windows, mais les coutures en python aussi sont cool =)
stefan83
1
@ stefan83: Python fonctionne aussi bien sur Windows.
David Foerster
3

Voici une ligne:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls imprime tous les fichiers du répertoire courant (dans l'ordre trié)
  2. sort dont_delete imprime tous les fichiers que nous ne voulons pas supprimer dans l'ordre trié
  3. le <() opérateur transforme une chaîne en un objet de type fichier
  4. le comm commandes comparent deux fichiers pré-triés et impriment des lignes sur lesquelles ils diffèrent
  5. l'utilisation des -2 -3drapeaux entraîne communiquement l'impression des lignes contenues dans le premier fichier mais pas le second, qui sera la liste des fichiers pouvant être supprimés en toute sécurité
  6. l' tail +2appel est simplement de supprimer l'en-tête ducomm sortie, qui contient le nom du fichier d'entrée
  7. Nous obtenons maintenant une liste de fichiers à supprimer lors de la sortie standard. Nous dirigeons cette sortie vers xargslaquelle transformera le flux de sortie en une liste d'arguments pour rm. L' -poption oblige xargsà demander une confirmation avant l'exécution.
gardenhead
la source
merci pour votre aide, maintenant j'ai ma solution!
stefan83
@gardenhead, j'ai fatigué votre code mais il supprime tous les fichiers du répertoire et ne conserve que le premier et le dernier fichier dans la liste dont-delete. avez-vous une idée de ce problème? Merci d'avance.
Negar
1

FWIW il semble que vous pouvez le faire en natif dans zsh , en utilisant le (+cmd)qualificatif 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

Tout d'abord, lisez la liste blanche dans un tableau:

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

ou peut-être mieux

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

(l'équivalent de la fonction mapfileintégrée de bash - ou son synonyme readarray). 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 l'utiliser pour créer une fonction qui renvoie trues'il n'y a aucune correspondance pour $REPLYdans 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 souhaiterez probablement ajouter le nom du fichier de liste blanche lui-même à la liste blanche.)

tournevis
la source
0

En supposant que votre shell bash est activé extglob shopt, voici une alternative un peu plus conservatrice:

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

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

conny
la source
0

À moins que la sortie de ls /home/me/myfolder2tocleanup/dépasse la limite d'argument shell maximale ARG_MAX qui est d'environ 2 Mo pour Ubuntu, je suggère ce qui suit.


Une implémentation de commande en ligne qui fera le travail serait la suivante:

  1. Copiez le dont-delete.txtfichier dans le répertoire contenant les fichiers à supprimer comme ceci:
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd dans le répertoire contenant les fichiers à supprimer comme ceci:
cd /home/me/myfolder2tocleanup/
  1. Effectuez un essai à blanc pour tester la commande et lui faire imprimer les noms des fichiers qu'elle détecte comme devant être supprimés sans les supprimer réellement, comme ceci:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. Si vous êtes satisfait de la sortie, supprimez les fichiers en exécutant la commande comme suit:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

Explication:

  • ls -plistera tous les fichiers et répertoires du répertoire courant et l'option -pajoutera a /aux noms de répertoire.
  • grep -v /exclura les répertoires en supprimant tous les éléments contenant un /dans leur nom.
  • sed 's/\<dont-delete.txt\>//g'exclura le dont-delete.txtfichier, il ne sera donc pas supprimé dans le processus.
  • sortva, juste pour être sûr, trier la sortie restante de ls.
  • comm -3 - <(sort dont-delete.txt)triera le dont-delete.txtfichier, le comparera à la sortie triée lset exclura les noms de fichiers qui existent dans les deux.
  • xargs rmsupprimera tous les noms de fichiers restants dans la sortie déjà traitée de ls. Cela signifie que tous les éléments du répertoire actuel seront supprimés, à l'exception des répertoires , des fichiers répertoriés dans le dont-delete.txtfichier et du dont-delete.txtfichier lui-même

Dans la partie sèche:

  • xargs echo imprimera les fichiers à supprimer.
  • tr " " "\n" traduira les espaces en nouvelles lignes pour une meilleure lisibilité.
Raffa
la source
0

Je suggère fortement d'utiliser la rsyncsolution publiée ici ; sinon utiliser la solution ci-dessous avec une condition exceptionnelle mentionnée.

En supposant qu'il n'y ait pas d'espaces (espaces / tabulations) dans vos fichiers 'répertoriés dans un fichier appelé excludelist, alors vous feriez:

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

Ajoutez simplement -deletela commande ci-dessus pour supprimer les fichiers qui n'existent pas dans le fichier excludelist . Si votre découverte n'a pas l' -deleteoption que vous pouvez utiliser rmavec -execcomme suit:

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

Ou utiliser -execavec +terminator à la place.

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

echo est juste utilisé pour un essai à sec.

αғsнιη
la source
-1

Ma suggestion est:

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

Mise à jour 2018-08-07

Exemple:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

Notez après la ligne 3 que vous aurez le dont-delete.txtfichier avec le contenu:

./a
./b
./dont-delete.txt

(le leader ./est très important )

Les fichiers cet dseront supprimés.

nyxz
la source
J'ai essayé cela avec un fichier texte des noms de fichiers séparés par une nouvelle ligne. Il a fini par supprimer tous les fichiers du répertoire.
Jacques MALAPRADE du
Je suppose que votre "liste de garde" était fausse.
nyxz
J'ai ajouté un exemple d'utilisation.
nyxz