À partir d'un script Shell, comment vérifier si un répertoire contient des fichiers?
Quelque chose de semblable à ceci
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
mais qui fonctionne si le répertoire contient un ou plusieurs fichiers (le précédent ne fonctionne qu'avec exactement 0 ou 1 fichiers).
Les solutions utilisées jusqu'ici utilisent ls
. Voici une solution tout bash:
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
Cette astuce est 100% bash
et appelle un sous-shell. L'idée est de Bruno De Fraine et améliorée par le commentaire de teambob .
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
Remarque: pas de différence entre un répertoire vide et un répertoire non existant (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 le 'officiel' FAQ pour #bash IRC canal :
if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
echo "contains files"
else
echo "empty (or does not exist, or is a file)"
fi
[ -n "$(ls -A your/dir)" ]
Cette astuce est inspirée de article de nixCraft posté en 2007. Ajoutez 2>/dev/null
pour supprimer l'erreur de sortie "No such file or directory"
.
Voir également la réponse de Andrew Taylor (2008) et la réponse de gr8can8dian (2011).
if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
echo "contains files (or is a file)"
else
echo "empty (or does not exist)"
fi
ou la version bashiste à une ligne:
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
Remarque: ls
renvoie $?=2
lorsque le répertoire n'existe pas. Mais pas de différence entre un fichier et un répertoire vide.
[ -n "$(find your/dir -Prune -empty)" ]
Cette dernière astuce est inspirée de réponse de gravstar où -maxdepth 0
est remplacé par -Prune
et amélioré par le commentaire de phils .
if [ -n "$(find your/dir -Prune -empty 2>/dev/null)" ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
une variante utilisant -type d
:
if [ -n "$(find your/dir -Prune -empty -type d 2>/dev/null)" ]
then
echo "empty directory"
else
echo "contains files (or does not exist or is not a directory)"
fi
Explication:
find -Prune
est similaire à find -maxdepth 0
en utilisant moins de caractèresfind -empty
imprime les répertoires et fichiers videsfind -type d
imprime uniquement les répertoires Remarque: Vous pouvez également remplacer [ -n "$(find your/dir -Prune -empty)" ]
par la version abrégée ci-dessous:
if [ `find your/dir -Prune -empty 2>/dev/null` ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
Ce dernier code fonctionne dans la plupart des cas, mais sachez que des chemins malveillants peuvent exprimer une commande ...
Que diriez-vous de ce qui suit:
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
De cette façon, il n'est pas nécessaire de générer une liste complète du contenu du répertoire. La read
permet à la fois de supprimer la sortie et de rendre l'expression évaluée à true uniquement lorsque quelque chose est lu (par exemple, /some/dir/
est trouvé vide par find
).
Essayer:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
if [ "$(ls -A $1)" ]; then
echo "huzzah"
else
echo "has no files"
fi
}
Attention aux répertoires avec beaucoup de fichiers! L'évaluation de la commande ls
peut prendre un certain temps.
OMI la meilleure solution est celle qui utilise
find /some/dir/ -maxdepth 0 -empty
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
Pourriez-vous comparer la sortie de ceci?
ls -A /some/dir | wc -l
# Vérifie si un répertoire contient des fichiers non cachés .____ # # # Usage: si vide "$ HOME"; puis echo "Bienvenue à la maison"; fi # isempty () { pour _ief en $ 1/*; faire si [-e "$ _ief"]; puis retourne 1 Fi terminé retourne 0 }
Quelques notes d'implémentation:
for
évite un appel à un processus externe ls
. 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
à l'intérieur de la boucle attrape le cas d'un répertoire vide, auquel cas la variable _ief
se verra attribuer la valeur "somedir/*" Ce n'est que si ce fichier existe que la fonction retournera "non vide"test
ne prend pas en charge l'indicateur -e
.Cela me dit si le répertoire est vide ou pas, le nombre de fichiers qu’il contient.
directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)
if [ "$number_of_files" == "0" ]; then
echo "directory $directory is empty"
else
echo "directory $directory contains $number_of_files files"
fi
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 un faux positif si des répertoires existent.
if find /path/to/check/* -maxdepth 0 -type f | read
then echo "Files Exist"
fi
dir_is_empty() {
[ "${1##*/}" = "*" ]
}
if dir_is_empty /some/dir/* ; then
echo "huzzah"
fi
Supposons que vous n'avez pas un fichier nommé *
dans /any/dir/you/check
, il devrait fonctionner sur bash
dash
posh
busybox sh
et zsh
mais (pour zsh) nécessite unsetopt nomatch
.
Les performances devraient être comparables à toutes les variables ls
qui utilisent *
(glob), je suppose que cela sera lent sur les répertoires avec beaucoup de noeuds (mon /usr/bin
avec plus de 3000 fichiers ne sera pas si lent), utilisera au moins assez de mémoire pour allouer tous les noms de fichiers/répertoires et plus) puisqu'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 d'arguments.
Un moyen rapide rapide O(1) de zéro ressource pour vérifier si un répertoire est vide serait agréable à avoir.
mettre à jour
La version ci-dessus ne prend pas en compte les fichiers/répertoires cachés, au cas où des tests supplémentaires seraient nécessaires, comme le is_empty
from from { astuces de Rich (sh (POSIX Shell))) :
is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )
Mais au lieu de cela, je pense à quelque chose comme ceci:
dir_is_empty() {
[ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}
Certaines inquiétudes concernant les différences finales entre les barres obliques et l'argument et la sortie de recherche lorsque le répertoire est vide, et les nouvelles lignes (mais cela devrait être facile à gérer), malheureusement sur ma busybox
sh
montrer ce qui est probablement un bogue sur le tube find -> dd
avec la sortie tronqué de manière aléatoire (si j'ai utilisé cat
la sortie est toujours la même, semble être dd
avec l'argument count
).
Je sais que la question était marquée pour bash; mais, juste pour référence, pour zsh users:
Pour vérifier si foo
est non vide:
$ for i in foo(NF) ; do ... ; done
où, si foo
n'est pas vide, le code du bloc for
sera exécuté.
Pour vérifier si foo
est vide:
$ for i in foo(N/^F) ; do ... ; done
où, si foo
est vide, le code du bloc for
sera exécuté.
Nous n'avons pas eu besoin de citer le répertoire foo
ci-dessus, mais nous pouvons le faire si nous avons besoin de:
$ for i in 'some directory!'(NF) ; do ... ; done
Nous pouvons également tester plusieurs objets, même s'il ne s'agit pas d'un répertoire:
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
Tout ce qui n'est pas un répertoire sera simplement ignoré.
Depuis que nous sommes en train de globbing, nous pouvons utiliser n’importe quel glob (ou expansion d’attelle):
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
Nous pouvons également examiner les objets placés dans un tableau. Avec les répertoires ci-dessus, par exemple:
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
Ainsi, nous pouvons tester des objets qui peuvent déjà être définis dans un paramètre de tableau.
Notez que le code du bloc for
est évidemment exécuté sur chaque répertoire. Si cela n'est pas souhaitable, vous pouvez simplement renseigner un paramètre de tableau, puis agir sur ce paramètre:
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
Pour les utilisateurs zsh, il existe le qualificatif (F)
glob (voir man zshexpn
), qui correspond aux répertoires "complets" (non vides):
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
Le qualificatif (F)
répertorie les objets qui correspondent à: est un répertoire ET n'est pas vide. Donc, (^F)
correspond: aucun répertoire OR n'est vide. Ainsi, (^F)
seul listerait également les fichiers normaux, par exemple. Ainsi, comme expliqué dans la page de manuel zshexp
, nous avons également besoin du qualificatif (/)
glob, qui répertorie uniquement les répertoires:
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
Ainsi, pour vérifier si un répertoire donné est vide, vous pouvez donc lancer:
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
et juste pour être sûr qu'un répertoire non vide ne sera pas capturé:
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
Oops! Puisque Y
n'est pas vide, zsh ne trouve aucune correspondance pour (/^F)
("les répertoires qui sont vides") et génère un message d'erreur indiquant qu'aucune correspondance pour le glob n'a été trouvée. Nous devons donc supprimer ces messages d'erreur possibles avec le qualificatif (N)
glob:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
Ainsi, pour les répertoires non vides, nous avons besoin du qualificatif (N/^F)
, que vous pouvez lire comme suit: "ne me prévenez pas des échecs, des répertoires qui ne sont pas pleins".
De même, pour les répertoires vides, nous avons besoin du qualificatif (NF)
, que nous pouvons également lire comme suit: "ne me prévenez pas des échecs, des répertoires complets".
Prenant un indice (ou plusieurs) de la réponse d’olibre, j’aime bien la fonction Bash:
function isEmptyDir {
[ -d $1 -a -n "$( find $1 -Prune -empty 2>/dev/null )" ]
}
Parce que même s’il crée un sous-shell, c’est aussi proche de la solution O(1) que je l’imagine et le nommer en le rendant lisible. Je peux alors écrire
if isEmptyDir somedir
then
echo somedir is an empty directory
else
echo somedir does not exist, is not a dir, is unreadable, or is not empty
fi
En ce qui concerne O(1), il existe des cas exceptionnels: si un répertoire volumineux a été effacé de la totalité ou de la totalité sauf la dernière entrée, il peut être nécessaire de "lire" l'intégralité du texte pour déterminer s'il est vide. Je pense que les performances attendues sont O(1), mais dans le pire des cas, la taille du répertoire est linéaire. Je n'ai pas mesuré cela.
Petite variation de réponse de Bruno :
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
Ça marche pour moi
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
Je suis surpris que le guide wooledge sur les répertoires vides n'ait pas été mentionné. Ce guide, et tous les éléments de Wooledge, est incontournable pour les questions de type Shell.
À noter de cette page:
N'essayez jamais d'analyser la sortie de ls. Même les solutions ls -A peuvent casser (par exemple, sur HP-UX, si vous êtes root, ls -A le fait. quelque chose qui incroyablement stupide).
En fait, on peut souhaiter éviter complètement la question directe. Habituellement, les gens veulent savoir si un Le répertoire est vide car ils veulent faire quelque chose avec les fichiers qu’ils contiennent, etc. Regardez le plus gros question. Par exemple, l'un de ces exemples basés sur la recherche peut constituer une solution appropriée:
# Bourne
find "$somedir" -type f -exec echo Found unexpected file {} \;
find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD
find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD
Le plus souvent, tout ce dont vous avez vraiment besoin est quelque chose comme ceci:
# Bourne
for f in ./*.mpg; do
test -f "$f" || continue
mympgviewer "$f"
done
En d'autres termes, la personne qui pose la question a peut-être pensé qu'un test de répertoire vide explicite était nécessaire pour éviter un message d’erreur tel que mympgviewer: ./*.mpg: Aucun fichier ou répertoire de ce type alors qu’en fait, aucun un tel test est requis.
J'irais pour find
:
if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
echo "$dir has NO files"
else
echo "$dir has files"
Ceci vérifie le résultat de la recherche de fichiers dans le répertoire, sans passer par les sous-répertoires. Ensuite, il vérifie la sortie à l'aide de l'option -z
tirée de man test
:
-z STRING
the length of STRING is zero
Voir quelques résultats:
$ mkdir aaa
$ dir="aaa"
Dir vide:
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
Juste dirs dedans:
$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
Un fichier dans le répertoire:
$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile
Un fichier dans un sous-répertoire:
$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
Avec quelques solutions de contournement, je pourrais trouver un moyen simple de savoir s'il existe des fichiers dans un répertoire. Cela peut s’étendre à d’autres avec les commandes grep pour vérifier spécifiquement les fichiers .xml ou .txt etc. Ex: ls /some/dir | grep xml | wc -l | grep -w "0"
#!/bin/bash
if ([ $(ls /some/dir | wc -l | grep -w "0") ])
then
echo 'No files'
else
echo 'Found files'
fi
Jusqu'à présent, je n'ai pas vu de réponse utilisant grep qui, à mon avis, donnerait une réponse plus simple (avec pas trop de symboles étranges!). Voici comment je voudrais vérifier si des fichiers existent dans le répertoire avec Bourne Shell:
cela retourne le nombre de fichiers dans un répertoire:
ls -l <directory> | egrep -c "^-"
vous pouvez renseigner le chemin du répertoire dans lequel répertoire est écrit. La première moitié du tube garantit que le premier caractère de la sortie est "-" pour chaque fichier. egrep compte ensuite le nombre de lignes commençant par ce symbole en utilisant des expressions régulières. tout ce que vous avez à faire est maintenant de stocker le nombre que vous avez obtenu et de le comparer à l’aide de citations arrières telles que:
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x est une variable de votre choix.
Essayez avec la commande find . Spécifiez le répertoire codé en dur ou comme argument . Ensuite, lance find pour rechercher tous les fichiers du répertoire . Vérifiez si return of find est null . Écho des données de find
#!/bin/bash
_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
echo -e "$_DIR contains files or subdirs with files \n\n "
echo "$_FIND"
else
echo "empty (or does not exist)"
fi
Réponse simple avec bash :
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
Mélanger des choses de pruneaux et les dernières réponses, je dois
find "$some_dir" -Prune -empty -type d | read && echo empty || echo "not empty"
cela fonctionne aussi pour les chemins avec des espaces