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.
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
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.
Voici un one-liner:
comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
ls
imprime tous les fichiers du répertoire en cours (par ordre de tri)sort dont_delete
imprime tous les fichiers que nous ne voulons pas supprimer par ordre de tri<()
transforme une chaîne en objet de type fichiercomm
comparent deux fichiers préalablement triés et impriment des lignes sur lesquelles ils diffèrent.-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é.tail +2
consiste simplement à supprimer l'en-tête de la sortie comm
, qui contient le nom du fichier d'entréexargs
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.FWIW, il semblerait que vous puissiez le faire de manière native dans zsh
name__, 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 mapfile
de bash - ou de son synonyme readarray
name__). 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 true
s'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.)
En supposant qu’il n’y ait pas d’espace (Espaces/Onglets) dans la liste de vos fichiers dans un fichier nommé list
name__, 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 rm
avec -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 {} +
echo
est simplement utilisé pour une exécution à sec.
En supposant que votre shell bash ait le extglob
shopt
activé, voici une alternative un peu plus conservatrice:
rm !($(tr \\n \| < keep.txt))
(... accompagnant sinon excellente suggestion de communication de @ gardenhead!)