Comment exclure certains fichiers du mécanisme d'extension de nom de fichier dans bash?

14

J'ai des répertoires de système de fichiers ubuntu dans le répertoire racine et j'ai accidentellement copié des centaines de fichiers dans le répertoire racine.

J'ai intuitivement essayé de supprimer les fichiers copiés en excluant le système de fichiers comme

rm -rf !{bin,sbin,usr,opt,lib,var,etc,srv,libx32,lib64,run,boot,proc,sys,dev} ./.

mais ça ne marche pas. Quelle est la bonne façon d'exclure certains répertoires tout en supprimant le tout?

EDIT: N'essayez jamais aucune des commandes ici sans savoir quoi faire!

kenn
la source
1
Quel shell utilisez-vous? Le globbing de nom de fichier dépend du shell quand il s'agit de faire des trucs fantaisistes comme ça.
Kusalananda
2
Pas une réponse, mais j'utiliserais par exemple mc. Sélectionnez tout avec *, puis désélectionnez des fichiers spécifiques avec la touche -ou Insert.
pbm
1
Pouvez-vous expliquer ce qu'est «mc»?
MikeP
@Kusalananda c'est/bin/bash
kenn
3
@MikeP: mcest Midnight Commander, une imitation très utile de Norton Commander. Il s'exécute dans un terminal. (Midnight Commander et Norton Commander sont des exemples de ce qu'on appelle un gestionnaire de fichiers orthodoxe .)
AlexP

Réponses:

21

Puisque vous utilisez bash:

shopt -s extglob
echo rm -rf ./!(bin|sbin|usr|...)

Je recommande d'ajouter echoau début de la ligne de commande lorsque vous exécutez quelque chose qui peut potentiellement faire exploser tout le système. Retirez-le si vous êtes satisfait du résultat.

Remarque: La commande ci-dessus ne supprimera pas les fichiers cachés (ceux dont le nom commence par un point). Si vous souhaitez également les supprimer, activez également l' dotgloboption:

shopt -s dotglob
jimmij
la source
Je l'ai utilisé pour nettoyer le système de fichiers avec succès. Au début, je l'ai testé dans un répertoire. J'ai également essayé la rm -rf ./!(bin,sbin,..)virgule séparément, mais elle supprime tous les répertoires.
kenn
Quelle est cette !(...)syntaxe? D'après l'exemple, je pensais intuitivement ls ./!(*/)ne répertorier que les fichiers, mais cela ne fonctionne pas de cette façon.
giusti
@giusti Cette syntaxe est une correspondance de modèle étendue dans le mécanisme d'expansion du nom de fichier - vous trouverez sa description dans le manuel bash sous le chapitre Expansion du nom de chemin. Il ne peut pas être utilisé pour exclure des types de fichiers, uniquement des noms, tout comme avec des étoiles *ou d'autres globes.
jimmij
12

Cette commande affichera tous les non-répertoires dans /:

find / -maxdepth 1 -type f

Une fois que vous avez tout à fait sûr qu'aucun fichier ne soit là que vous souhaitez conserver, vous pouvez utiliser:

find / -maxdepth 1 -type f -delete

Plus sûr, ce serait de les déplacer ailleurs pour vous assurer de ne pas supprimer quelque chose que vous souhaitez conserver:

mkdir /root/preserve
find / -maxdepth 1 -type f -exec mv -- "{}" /root/preserve/\;

Si, en plus des fichiers, vous avez également des répertoires que vous avez ajoutés à la racine du système de fichiers, cela pourrait être automatisé en excluant les répertoires LSB d'un automatisé mvou rm, mais honnêtement, puisque nous avons affaire à la purge des choses dans le racine du système de fichiers, je vous suggère fortement d'envisager de le faire manuellement si possible.

Si ce n'est pas possible, quelque chose comme ça pourrait faire l'affaire:

#!/bin/bash
declare -a excludes
for item in root sys 'lost+found' mnt home proc etc opt boot lib lib64 libx32 sbin media srv dev var usr bin tmp run; do
    excludes+=("$item")
done
if ! [[ -d /root/preserve ]]; then
    mkdir -p /root/preserve
fi
IFS="\n"
for item in find / -type d -maxdepth 1; do
    really=true
    for exclude in ${excludes[@]}; do
        if [[ "$exclude" == "${item#/}" ]]; then
            really=false
        fi
    done
    if [[ "true" == "$really" ]]; then
        mv -- "$item" /root/preserve/
    fi
done

Une fois que vous avez réussi le test de cri (c'est-à-dire que votre système fonctionne toujours et que vous ne criez pas dans l'angoisse), vous pouvez supprimer le contenu de /root/preserve/.

Remarque importante: quoi que vous fassiez, ne pensez même pas à exécuter une permutation de rm -fr [ANYTHING GOES HERE] /.

DopeGhoti
la source
votre solution ne supprime que les fichiers mais il y a aussi des dossiers autour.
kenn
1
Une fois de trop, j'ai entendu des cris de consternation d'un mal visé rm. Comme un script avec rm -fr $somepath/avec somepathnon initialisé. J'aurais pu aller plus loin en exprimant la gravité de cette situation, mais j'ai choisi de rester favorable à la famille dans mon avertissement.
DopeGhoti
3

Cela devrait faire le travail (mais pas de la même manière que le PO le demande):

ls -1 >1.txt
pico 1.txt 

supprimez tous les fichiers / répertoires que vous souhaitez conserver

xargs rm < 1.txt

Si vos fichiers ont tous le même format de nom, la même date ou autre chose, il existe d'autres méthodes.

Je regarderais les inodes - et verrais s'ils sont séquentiels via ls -i | sort et s'ils le sont, alors les nouveaux fichiers auront des inodes plus grands. Ensuite, en utilisant le même type de processus que ci-dessus ...

ls -iF1 | sort |cut -c10- | grep -vE "\/|\@" >i.txt   #This part removes entries that are not regular files, such as directories and links.  
pico i.txt
xargs rm < i.txt

dans la commande cut ci-dessus, vérifiez d'abord votre liste d'inodes pour vous assurer que c'est la bonne quantité.

MikeP
la source