Recherche de répertoires vides UNIX

91

J'ai besoin de trouver des répertoires vides pour une liste donnée de répertoires. Certains répertoires contiennent des répertoires.

Si les répertoires internes sont également vides, je peux dire que le répertoire principal est vide, sinon il n'est pas vide.

Comment puis-je tester cela?

Par exemple:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty
soField
la source
2
Je pense que la réponse de Martin est la plus appropriée ici. La réponse actuellement acceptée n'est qu'un pseudocode incomplet.
Léo Léopold Hertz 준영

Réponses:

34

Vérifiez si find <dir> -type fquelque chose sort. Voici un exemple:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Marcelo Cantos
la source
2
Non, il ne produira pas de sous-répertoires. C'est à cela que -type fsert.
Marcelo Cantos
Howerver s'il y a des fichiers vides , votre solution ne donnera pas le message.
Yasir Arsanukaev
3
Yasir: Je pense qu'un répertoire contenant un fichier vide n'est pas lui-même vide. Ne serait-ce pas le résultat correct?
Ukko
2
@akostadinov: Si je crée les répertoires et les fichiers comme indiqué par l'OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- et exécute le code dans ma réponse, il signale que B et C sont vides, comme requis par l'OP. Vous devrez donc être un peu plus précis que «cela ne fonctionnera pas».
Marcelo Cantos
1
Si vous êtes un noob Bash comme moi, vérifiez ce que signifie -z ici .
OmarOthman
257

Cela dépend un peu de ce que vous voulez faire avec les répertoires vides. J'utilise la commande ci-dessous lorsque je souhaite supprimer tous les répertoires vides dans une arborescence, par exemple testrépertoire.

find test -depth -empty -delete

Une chose à noter à propos de la commande ci-dessus est qu'elle supprimera également les fichiers vides , utilisez donc l' option -type d pour éviter cela.

find test -depth -type d -empty -delete

Déposez -deletepour voir les fichiers et répertoires correspondants.

Si votre définition d'une arborescence de répertoires vide est qu'elle ne contient aucun fichier, vous pouvez alors coller quelque chose ensemble en fonction du find test -type fretour ou non.

find est un excellent utilitaire, et RTFM tôt et souvent pour vraiment comprendre tout ce qu'il peut faire :-)

Martin
la source
8
-delete implique -depth (au moins pour GNU findutils 4.4.2)
Personne II
4
ne savait pas -empty, si pratique!
Raffi
2
Cependant, sur des machines qui ne sont pas les derniers et les meilleurs Linux. (EG Solaris), alors vous n'avez aucune fonctionnalité de recherche sophistiquée comme -empty ou -delete.
anthony
3
Sous MacOS-X, pour les répertoires presque vides, exécutez d' find test -name ".DS_Store" -deleteabord, puis la -empty deletecommande. Notez également, comme pour pushdle répertoire parent, ce qui find testdevient find ., mais le reste des commandes sont les mêmes.
Olie
1
@Martin Pouvez-vous s'il vous plaît ajouter la définition de -depthici, c.-à-d. Cause find pour effectuer une traversée en profondeur d'abord, c'est-à-dire que les répertoires sont visités dans l'ordre postérieur et que toutes les entrées d'un répertoire agiront avant le répertoire lui-même. Je pense que c'est pertinent ici.
Léo Léopold Hertz 준영
49

Vous pouvez utiliser la commande suivante:

find . -type d -empty
mosg
la source
1
-empty ne fonctionne que si le répertoire courant est complètement vide, pas si le sous-arbre ne contient aucun fichier.
Marcelo Cantos
@soField Testé trouver. -type d -empty avec FreeBSD et CentOS. Fonctionne très bien. Quel est votre système d'exploitation?
mosg
1
hp-ux donc il n'y a pas de paramètre vide
soField
@soField Donc, vous voyez, il vaut mieux (pour nous tous) de publier ces données en haut de votre question ...
mosg
2
find n'a pas non plus -empty sur solaris, mais il a -depth pour appliquer la traversée en profondeur afin que les sous-répertoires vides puissent être supprimés avant que le répertoire parent ne soit vérifié pour la vacuité.
eirikma
26
find directory -mindepth 1 -type d -empty -delete

C'est la version que j'ai trouvée la plus intéressante. S'il est exécuté depuis l'intérieur du répertoire , il supprimera tous les répertoires vides ci-dessous (un répertoire est considéré comme vide s'il ne contient que des répertoires vides).

L'option mindepth empêche le répertoire lui-même d'être supprimé s'il est vide.

Dr Personne Personne II
la source
2
Vous pouvez continuer avec rmdir --ignore-fail-on-non-empty -p directorypour vous débarrasser des parents.
Pete Peterson du
@Pete Peterson Ma commande semble supprimer les répertoires qui ne contiennent que d'autres répertoires vides (ce que OP semble également vouloir). Je note que votre commande laissera généralement l'utilisateur dans un répertoire avec un i-node manquant même s'il accomplit ce qu'il veut, ce qui peut être déroutant pour lui. Peut-être que je rate le point.
Dr Person Person II
23

find . -type d -empty

trouve et répertorie les répertoires et sous-répertoires vides dans l'arborescence actuelle. Par exemple, la liste résultante de répertoires et sous-répertoires vides:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

Aucune opération n'est effectuée sur les répertoires. Ils sont simplement listés. Cela fonctionne pour moi.

user7194913
la source
16

Il suffit de trouver des répertoires vides

Afin de ne trouver que les répertoires vides (comme spécifié dans le titre de la question), la réponse du mosg est correcte:

find -type d -empty

Mais -emptypeut ne pas être disponible sur des findversions très anciennes (c'est le cas de HP-UX par exemple). Si tel est votre cas, consultez les techniques décrites dans la section ci-dessous Un répertoire est-il vide? .

Supprimer les répertoires vides

C'est un peu délicat: supposons qu'un répertoire MyDircontienne des répertoires vides. Après avoir supprimé ces répertoires vides, MyDirdeviendra un répertoire vide et devrait également être supprimé. Par conséquent, j'utilise la commande rmdiravec l'option --parents(ou -p) qui supprime également les répertoires parents lorsque cela est possible:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

Sur les anciennes findversions, l'instruction +n'est pas encore prise en charge, vous pouvez donc utiliser à la ;place:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

Un répertoire est-il vide?

La plupart de ces réponses expliquent comment vérifier si un répertoire est vide. Par conséquent, je propose ici les trois techniques différentes que je connais:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi

    une variante:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi

    Explication:

    • find -pruneest similaire à l' find -maxdepth 0utilisation de moins de caractères
    • find -type d imprime uniquement les répertoires
    • find -empty imprime les répertoires et fichiers vides

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
  2. (( ${#files} ))

    Cette astuce est à 100% bashmais invoque (génère) un sous-shell. L'idée est de Bruno De Fraine et améliorée par le commentaire de teambob . Je conseille celui-ci si vous utilisez et si votre script n'a pas besoin d'être portable.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi

    Note: pas de différence entre un répertoire vide et un répertoire inexistant (et même lorsque le chemin fourni est un fichier).

  3. [ $(ls -A your/dir) ]

    Cette astuce est inspirée de l'article de nixCraft publié en 2007. Andrew Taylor a répondu en 2008 et gr8can8dian en 2011.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi

    ou la version bashisme en une ligne:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."

    Remarque: ls retourne $?=2lorsque le répertoire n'existe pas. Mais aucune différence entre un fichier et un répertoire vide.

olibre
la source
rmdir -vpm'a énormément aidé car je devais non seulement supprimer tous les répertoires vides sous une racine, mais vérifier les répertoires vides et les répertoires parents après la suppression d'un fichier. Dans ma situation, les répertoires vides conviennent tant qu'ils ne sont pas dans l'arborescence dont je supprime actuellement un fichier. Merci!
Ethan Hohensee
2

Cette fonction récursive semble faire l'affaire:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Compte tenu de cet exemple de structure de répertoire:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- fichier5
    | - dir4 /
    | | - dirD /
    | `- fichier4
    `- dir5 /
        `- dirE /
            `- dir_V /

Le résultat de l'exécution de cette fonction serait:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

qui manque /dir4/dirD. Si vous déplacez l'appel récursif findempty "$dir"après le fi, la fonction inclura ce répertoire dans ses résultats.

Suspendu jusqu'à nouvel ordre.
la source
2

Et pourquoi pas rmdir *? Cette commande échouera sur les répertoires non vides.

Evandrix
la source
Quelque chose que j'ai fait parfois, pour le nettoyage général. Également fait des choses comme rmdir */*/* */* * Bien que cela ne gère pas les «fichiers à points», mais dans des situations manuelles (nettoyage de fichiers de données), vous ne vous attendez généralement pas à des «fichiers à points». Cependant, les méthodes récursives sont destinées à un nettoyage général plus automatisé, en particulier dans les très grandes structures de répertoires.
anthony le
Dans un cas, c'était plus compliqué car je devais supprimer les répertoires vides où «vides» incluaient des répertoires pouvant contenir un seul fichier «readme». Tout le reste dans le répertoire et ce n'était pas «vide». Dans cet exemple, la structure des répertoires impliquait des dizaines de milliers de sous-répertoires.
anthony le
1

La commande suivante renvoie 1 si un répertoire est vide (ou n'existe pas) et 0 sinon (il est donc possible d'inverser le code de retour avec !dans un script shell):

find $dir -type d -prune -empty -exec false {} +
Mateusz Piotrowski
la source
0

J'ai créé une structure simple comme suit:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

Le test/test3/filecontient du texte indésirable.

L'émission find test -emptyrenvoie " test/test2/test2.2" comme seul répertoire vide.

James Sumners
la source
l'op demande que test / test2 soit renvoyé aussi
En effet. Mais j'ai pensé qu'il pouvait lire la page de manuel find pour aller plus loin. Un script qui ajuste les profondeurs en fonction des résultats fonctionnerait très bien.
James Sumners
C'était la version la plus utile pour mon utilisation, merci
Andreas
0

une approche simple serait,

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

aussi,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"
phénix24
la source
0
find . -name -type d -ls |awk '($2==0){print $11}'
Vijay
la source