2011-10-31 03:47:31 +0000 2011-10-31 03:47:31 +0000
106
106

Bash scripting : test pour un répertoire vide

Je veux tester si un répertoire ne contient pas de fichiers. Si c'est le cas, je vais sauter certains traitements.

J'ai essayé ce qui suit :

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

Cela donne l'erreur suivante :

line 1: [: too many arguments

Y a-t-il une solution/alternative ?

Réponses (18)

135
135
135
2011-10-31 03:53:28 +0000
if [-z "$(ls -A /path/to/dir)"]; then
   echo "Empty"
else
   echo "Not Empty"
fi

Aussi, il serait bien de vérifier si le répertoire existe déjà.

24
24
24
2013-10-29 21:07:29 +0000

Pas besoin de compter quoi que ce soit ou de se contenter d'une coquille. Vous pouvez également utiliser read en combinaison avec find. Si la sortie de find est vide, vous retournerez false :

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

Ceci devrait être portable.

20
20
20
2011-10-31 10:53:57 +0000
if [-n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)"]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi
14
14
14
2011-11-01 14:51:09 +0000
#!/bin/bash
if [-d /path/to/dir]; then
    # the directory exists
    ["$(ls -A /path/to/dir)"] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [-f /path/to/dir]
fi
4
4
4
2018-09-26 13:50:40 +0000

Avec FIND(1) (sous Linux et FreeBSD), vous pouvez regarder de manière non récursive une entrée de répertoire via “-maxdepth 0” et tester si elle est vide avec “-empty”. Appliqué à la question que cela donne :

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi
4
4
4
2014-10-24 01:23:28 +0000

Une façon de faire sans PID, hacky mais bash-only :

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1) return 0 ;;
        *) return 1 ;;
    esac
}

Cela tire parti du fait que test builtin sort avec 2 si on lui donne plus d'un argument après -e : D'abord, "$1"/* glob est étendu par bash. Il en résulte un argument par fichier. Donc

  • S'il n'y a pas de fichiers, l'astérisque dans test -e "$1"* ne se développe pas, donc le Shell revient à essayer le fichier nommé *, qui renvoie 1.

  • …sauf s'il y a effectivement un fichier nommé exactement *, alors l'astérisque se développe pour devenir bien, asterisk, qui finit par le même appel que ci-dessus, c'est-à-dire test -e "dir/*", mais cette fois-ci il renvoie 0 (merci @TrueY de nous l'avoir fait remarquer). )

  • S'il y a un fichier, test -e "dir/file" est exécuté, ce qui renvoie 0.

  • Mais s'il y a plus de fichiers que 1, test -e "dir/file1" "dir/file2" est exécuté, ce qui signale une erreur d'utilisation, c'est-à-dire 2.

case enroule toute la logique de sorte que seul le premier cas, avec un statut de sortie, est signalé comme un succès.

Problèmes possibles que je n'ai pas vérifiés :

  • Il y a plus de fichiers que le nombre d'arguments autorisés - je suppose que cela pourrait se comporter de la même manière que dans le cas de 2+ fichiers.

  • Ou il y a en fait un fichier avec un nom vide - je ne suis pas sûr que ce soit possible sur un OS/FS sain.

4
4
4
2011-10-31 10:06:28 +0000

Cela fera le travail dans le répertoire de travail actuel (.) :

[`ls -1A . | wc -l` -eq 0] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

ou la même commande divisée sur trois lignes juste pour être plus lisible :

[`ls -1A . | wc -l` -eq 0] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

Il suffit de remplacer ls -1A . | wc -l par ls -1A <target-directory> | wc -l si vous devez l'exécuter sur un dossier cible différent.

Editer : J'ai remplacé -1a par -1A (voir le commentaire de @Daniel)

3
3
3
2011-10-31 10:17:15 +0000

Utilisez ce qui suit :

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [$count -eq 0] ; then
   echo "No new file"
   exit 1
fi

De cette façon, vous êtes indépendant du format de sortie de ls. -mindepth saute le répertoire lui-même, -maxdepth empêche de se défendre récursivement dans des sous-répertoires pour accélérer les choses.

3
3
3
2014-08-12 21:46:08 +0000

En utilisant un tableau :

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi
2
2
2
2018-06-20 09:17:01 +0000

Que diriez-vous de tester si le répertoire existe et s'il n'est pas vide dans l'une des déclarations

if [[-d path/to/dir && -n "$(ls -A path/to/dir)"]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi
```.
1
1
1
2013-10-29 20:57:27 +0000

Je pense que la meilleure solution est :

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[["$files"]] || echo "dir empty"

grâce à https://stackoverflow.com/a/91558/520567

Il s'agit d'une modification anonyme de ma réponse qui pourrait ou non être utile à quelqu'un : Une légère altération donne le nombre de fichiers :

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

Cela fonctionnera correctement même si les noms de fichiers contiennent des espaces.

1
1
1
2020-02-16 18:53:46 +0000

La question était:

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

La réponse est:

if ls -1qA . | grep -q .
    then ! exit 1
    else : # Dir is empty
fi
```.
1
1
1
2018-05-25 17:06:53 +0000
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

EDIT : Je pense que cette solution fonctionne bien avec gnu find, après un rapide regard sur la implémentation . Mais cela peut ne pas fonctionner avec, par exemple, netbsd’s find . En effet, celui-ci utilise le champ st_size de stat(2). Le manuel le décrit ainsi :

st_size The size of the file in bytes. The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory. Some may also return other
                   things or always report zero.

Une meilleure solution, également plus simple, est :

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

Aussi, le -prune dans la 1ère solution est inutile.

EDIT : no -exit for gnu find… la solution ci-dessus est bonne pour la find de NetBSD. Pour GNU find, cela devrait fonctionner :

if [-z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`"]; then
    echo Empty
else
    echo Not Empty
fi
0
0
0
2020-01-15 17:46:01 +0000

J'ai fait cette approche :

CHECKEMPTYFOLDER=$(test -z "$(ls -A /path/to/dir)"; echo $?)
if [$CHECKEMPTYFOLDER -eq 0]
then
  echo "Empty"
elif [$CHECKEMPTYFOLDER -eq 1]
then
  echo "Not Empty"
else
  echo "Error"
fi
0
0
0
2018-05-02 13:29:51 +0000

Cela fonctionne pour moi, pour vérifier et traiter les fichiers dans le répertoire ../IN, considérant que le script est dans le répertoire ../Script :

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code
0
0
0
2012-02-24 10:06:37 +0000

Tout cela est très bien - j'ai juste fait un script pour pouvoir vérifier s'il y a des répertoires vides en dessous du répertoire actuel. Le répertoire ci-dessous doit être placé dans un fichier appelé “findempty”, placé dans le chemin d'accès quelque part pour que bash puisse le trouver et ensuite chmod 755 pour l'exécuter. Il peut facilement être modifié en fonction de vos besoins spécifiques.

#!/bin/bash
if ["$#" == "0"]; then 
find . -maxdepth 1 -type d -exec findempty "{}" \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if ["$COUNT" == "0"]; then 
echo "$* : $COUNT"
fi
-1
-1
-1
2018-01-10 17:12:56 +0000

Pour tout autre répertoire que le répertoire courant, vous pouvez vérifier s'il est vide en essayant de le mettre à rmdir car rmdir est garanti d'échouer pour les répertoires non vides. Si rmdir réussit, et que vous vouliez vraiment que le répertoire vide survive au test, il suffit de mkdir it à nouveau.

N'utilisez pas ce hack s'il y a d'autres processus qui pourraient être déstabilisés par un répertoire dont ils savent qu'il a brièvement cessé d'exister.

Si rmdir ne fonctionne pas pour vous, et que vous testez des répertoires qui pourraient potentiellement contenir un grand nombre de fichiers, toute solution reposant sur le “shell globbing” pourrait devenir lente et/ou se heurter aux limites de longueur de la ligne de commande. Dans ce cas, il est probablement préférable d'utiliser find. La solution find la plus rapide à laquelle je puisse penser est la suivante :

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

Cela fonctionne pour les versions GNU et BSD de find mais pas pour celle de Solaris, qui ne dispose pas de tous les opérateurs find. J'adore votre travail.

-3
-3
-3
2018-04-08 20:54:13 +0000

Vous pouvez essayer de supprimer le répertoire et attendre une erreur ; rmdir ne supprimera pas le répertoire s'il n'est pas vide.

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi