À partir d'un script shell, comment vérifier si un répertoire contient des fichiers?
Quelque chose de semblable à ça
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
mais qui fonctionne si le répertoire contient un ou plusieurs fichiers (celui ci-dessus ne fonctionne qu'avec exactement 0 ou 1 fichiers).
Réponses:
Les solutions utilisées jusqu'ici
ls
. Voici une solution tout bash:la source
shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
alors l'instruction if devrait changer enif [ ${#files} -gt 0 ];
ou peut-être avez-vous simplement oublié le () autour de la commande du sous-shell?files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
Trois meilleurs trucs
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
Cette astuce est à 100%
bash
et invoque (génère) un sous-shell. L'idée est de Bruno De Fraine et améliorée par le commentaire de teambob .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).
Il existe une alternative similaire et plus de détails (et plus d'exemples) sur la FAQ `` officielle '' du canal IRC #bash :
[ -n "$(ls -A your/dir)" ]
Cette astuce est inspirée de l'article de nixCraft publié en 2007. Ajoutez
2>/dev/null
pour supprimer l'erreur de sortie"No such file or directory"
.Voir aussi la réponse d' Andrew Taylor (2008) et la réponse de gr8can8dian (2011).
ou la version bashisme en une ligne:
Remarque:
ls
retourne$?=2
lorsque le répertoire n'existe pas. Mais aucune différence entre un fichier et un répertoire vide.[ -n "$(find your/dir -prune -empty)" ]
Cette dernière astuce est inspirée de la réponse de gravstar où
-maxdepth 0
est remplacé-prune
et amélioré par le commentaire de phils .une variante utilisant
-type d
:Explication:
find -prune
est similaire à l'find -maxdepth 0
utilisation de moins de caractèresfind -empty
imprime les répertoires et fichiers videsfind -type d
imprime uniquement les répertoiresRemarque: vous pouvez également remplacer
[ -n "$(find your/dir -prune -empty)" ]
uniquement par la version raccourcie ci-dessous:Ce dernier code fonctionne dans la plupart des cas mais sachez que des chemins malveillants pourraient exprimer une commande ...
la source
[ -n "$(find "your/dir" -prune -empty)" ]
pour éviter la répétition du chemin du répertoire.if [ ``ls -A your/dir`` ]
dans un script, je suis arrivé à la conclusion que cela fonctionne bien pour un répertoire avec 0, 1 ou 2 sous-répertoires, mais échoue pour un répertoire avec plus de 2 sous-répertoires.line 17: [: 20150424-002813: unary operator expected
où20150424-002813
était l'un des noms de répertoire. La coquille utilisée était/bin/bash/
. Je l'ai finalement changé enls "$destination" | tail -1
if [ ``ls -A my/dir`` ]
sort par erreurbash: [: -A: binary operator expected
. Testé sur les versions bash 4.1.2 et 4.2.53.-n
variante était dans le titre mais pas dans le paragraphe ci-dessous). Alors, oui, ça va.ls: cannot access '/path': No such file or directory
. Existe-t-il un moyen de supprimer ce message? Je voudrais y échouer en silence.Que diriez-vous de ce qui suit:
De cette façon, il n'est pas nécessaire de générer une liste complète du contenu du répertoire. Le
read
est à la fois de rejeter la sortie et de rendre l'expression évaluée à vrai uniquement lorsque quelque chose est lu (c'est/some/dir/
-à- dire trouvé vide parfind
).la source
find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
ls
sortie et ne repose pas sur des fonctionnalités de shell non par défaut.-maxdepth
et les-empty
primaires.Essayer:
la source
/bin/ls <some_dir>/* 2> /dev/null
si [! -z "$ tmp"]; puis echo Quelque chose est là fils /some/dir/*
]; puis echo "huzzah"; fi-n
place de! -z
(ils sont tous les deux équivalents, mais pourquoi ne pas utiliser la forme la plus courte lorsqu'elle existe).BigGray% if [ ! -z
ls / some / dir / * `]; puis echo "huzzah"; fi zsh: aucune correspondance trouvée: / some / dir / * `ls...
dans bashla source
Faites attention aux répertoires contenant beaucoup de fichiers! L'évaluation de la
ls
commande peut prendre un certain temps .IMO la meilleure solution est celle qui utilise
la source
la source
Pourriez-vous comparer la sortie de ceci?
la source
Quelques notes de mise en œuvre:
for
boucle évite un appel à unls
processus externe . Il lit toujours toutes les entrées du répertoire une fois. Cela ne peut être optimisé qu'en écrivant un programme C qui utilise explicitement readdir ().test -e
intérieur de la boucle attrape le cas d'un répertoire vide, auquel cas la variable se_ief
verrait attribuer la valeur "somedir / *". Ce n'est que si ce fichier existe que la fonction retournera "non vide"test
implémentation ne prend pas en charge le-e
drapeau.la source
dotglob
n'est pas défini -shopt -s dotglob
Cela me dit si le répertoire est vide ou si ce n'est pas le cas, le nombre de fichiers qu'il contient.
la source
ls
.Cela peut être une réponse très tardive, mais voici une solution qui fonctionne. Cette ligne ne reconnaît que l'existence de fichiers! Cela ne vous donnera pas de faux positif si des répertoires existent.
la source
Supposons que vous ne disposez pas d'un fichier nommé
*
dans/any/dir/you/check
, il doit travaillerbash
dash
posh
busybox sh
etzsh
mais (pour zsh) exigentunsetopt nomatch
.Les performances devraient être comparables à celles
ls
qui utilisent*
(glob), je suppose que ce sera lent sur les répertoires avec de nombreux nœuds (mon/usr/bin
avec plus de 3000 fichiers n'est pas si lent), utilisera au moins assez de mémoire pour allouer tous les répertoires / noms de fichiers (et plus) comme ils sont tous passés (résolus) à la fonction en tant qu'arguments, certains shell ont probablement des limites sur le nombre d'arguments et / ou la longueur des arguments.Un moyen portable rapide O (1) zéro ressources pour vérifier si un répertoire est vide serait bien d'avoir.
mettre à jour
La version ci-dessus ne tient pas compte des fichiers / répertoires cachés, au cas où des tests supplémentaires seraient nécessaires, comme les astuces
is_empty
de Rich's sh (shell POSIX) :Mais, à la place, je pense à quelque chose comme ça:
Une certaine inquiétude concernant les différences de barres obliques de fin par rapport à l'argument et la sortie de recherche lorsque le répertoire est vide, et les nouvelles lignes de fin (mais cela devrait être facile à gérer), malheureusement, dans mon
busybox
sh
émission, ce qui est probablement un bogue sur lefind -> dd
tube avec la sortie tronquée de manière aléatoire ( si j'ai utilisécat
la sortie est toujours la même, semble êtredd
avec l'argumentcount
).la source
is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
ZSH
Je sais que la question a été marquée pour bash; mais, juste pour référence, pour les utilisateurs zsh :
Tester le répertoire non vide
Pour vérifier si ce
foo
n'est pas vide:où, si
foo
n'est pas vide, le code dufor
bloc sera exécuté.Tester le répertoire vide
Pour vérifier si
foo
est vide:où, si
foo
est vide, le code dufor
bloc sera exécuté.Remarques
Nous n'avons pas eu besoin de citer le répertoire
foo
ci-dessus, mais nous pouvons le faire si nous devons:Nous pouvons également tester plus d'un objet, même s'il ne s'agit pas d'un répertoire:
Tout ce qui n'est pas un répertoire sera simplement ignoré.
Suppléments
Puisque nous sommes en train de globbing, nous pouvons utiliser n'importe quel glob (ou extension d'accolades):
Nous pouvons également examiner les objets placés dans un tableau. Avec les répertoires comme ci-dessus, par exemple:
Ainsi, nous pouvons tester des objets qui peuvent déjà être définis dans un paramètre de tableau.
Notez que le code dans le
for
bloc est, évidemment, exécuté sur chaque répertoire à tour de rôle. Si cela n'est pas souhaitable, vous pouvez simplement renseigner un paramètre de tableau, puis opérer sur ce paramètre:Explication
Pour les utilisateurs de zsh, il y a le
(F)
qualificatif glob (voirman zshexpn
), qui correspond aux répertoires "pleins" (non vides):Le qualificatif
(F)
répertorie les objets qui correspondent: est un répertoire ET n'est pas vide. Donc,(^F)
correspond: pas un répertoire OU est vide. Ainsi,(^F)
seul listerait également les fichiers réguliers, par exemple. Ainsi, comme expliqué sur lazshexp
page de manuel, nous avons également besoin du(/)
qualificatif glob, qui répertorie uniquement les répertoires:Ainsi, pour vérifier si un répertoire donné est vide, vous pouvez donc lancer:
et juste pour être sûr qu'un répertoire non vide ne serait pas capturé:
Oups! Puisqu'il
Y
n'est pas vide, zsh ne trouve aucune correspondance pour(/^F)
("répertoires qui sont vides") et crache donc un message d'erreur indiquant qu'aucune correspondance pour le glob n'a été trouvée. Nous devons donc supprimer ces éventuels messages d'erreur avec le(N)
qualificatif glob:Ainsi, pour les répertoires vides, nous avons besoin du qualificatif
(N/^F)
, que vous pouvez lire comme: "ne me prévenez pas des pannes, des répertoires qui ne sont pas pleins".De même, pour les répertoires non vides, nous avons besoin du qualificatif
(NF)
, que nous pouvons également lire comme: "ne me prévenez pas des pannes, répertoires complets".la source
Je suis surpris que le guide Wooledge sur les répertoires vides n'ait pas été mentionné. Ce guide, et tout le Wooledge vraiment, est une lecture incontournable pour les questions de type coquille.
À noter sur cette page:
la source
Petite variation de la réponse de Bruno :
Ça marche pour moi
la source
Prenant un indice (ou plusieurs) de la réponse d'Olibre, j'aime une fonction Bash:
Parce que bien qu'il crée un sous-shell, il est aussi proche d'une solution O (1) que je peux l'imaginer et lui donner un nom le rend lisible. Je peux alors écrire
En ce qui concerne O (1), il existe des cas aberrants: si un grand répertoire a eu tout ou tout, sauf la dernière entrée supprimée, «find» peut devoir lire le tout pour déterminer s'il est vide. Je crois que les performances attendues sont O (1) mais le pire des cas est linéaire dans la taille du répertoire. Je n'ai pas mesuré cela.
la source
Jusqu'à présent, je n'ai pas vu de réponse utilisant grep qui, je pense, donnerait une réponse plus simple (avec pas trop de symboles étranges!). Voici comment je vérifierais si des fichiers existent dans le répertoire en utilisant bourne shell:
ceci renvoie le nombre de fichiers dans un répertoire:
vous pouvez remplir le chemin du répertoire dans lequel le répertoire est écrit. La première moitié du tube garantit que le premier caractère de sortie est "-" pour chaque fichier. egrep compte ensuite le nombre de lignes commençant par ce symbole à l'aide d'expressions régulières. maintenant, tout ce que vous avez à faire est de stocker le numéro que vous obtenez et de le comparer en utilisant des guillemets comme:
x est une variable de votre choix.
la source
Mélanger les choses de pruneau et les dernières réponses, je suis arrivé à
qui fonctionne aussi pour les chemins avec des espaces
la source
Réponse simple avec bash :
la source
J'irais pour
find
:Cela vérifie le résultat de la recherche de fichiers uniquement dans le répertoire, sans passer par les sous-répertoires. Ensuite, il vérifie la sortie en utilisant l'
-z
option tirée deman test
:Voir quelques résultats:
Rép vide:
Juste dirs dedans:
Un fichier dans le répertoire:
Un fichier dans un sous-répertoire:
la source
Avec une solution de contournement, je pourrais trouver un moyen simple de savoir s'il y a des fichiers dans un répertoire. Cela peut s'étendre avec d'autres commandes grep pour vérifier spécifiquement les fichiers .xml ou .txt, etc. Ex:
ls /some/dir | grep xml | wc -l | grep -w "0"
la source
la source
nullglob
, car lals
commande réussira.pour tester un répertoire cible spécifique
la source
Essayez avec la commande find. Spécifiez le répertoire codé en dur ou comme argument. Ensuite, lancez la recherche pour rechercher tous les fichiers dans le répertoire. Vérifiez si le retour de la recherche est nul. Faire écho aux données de trouver
la source
Je n'aime pas le
ls - A
solutions affichées. Vous souhaiterez probablement tester si le répertoire est vide car vous ne souhaitez pas le supprimer. Ce qui suit fait cela. Si toutefois vous souhaitez simplement enregistrer un fichier vide, il est sûrement plus rapide de le supprimer et de le recréer que de lister éventuellement des fichiers infinis?Cela devrait fonctionner ...
la source
${target}/..
.Fonctionne bien pour moi ceci (quand dir existe):
Avec contrôle complet:
la source