web-dev-qa-db-fra.com

Compter les fichiers et les répertoires à l'aide du script Shell

J'apprends le script bash et j'ai écrit un script pour compter les fichiers et répertoires dans le répertoire fourni en argument. Je le fais fonctionner d'une manière qui me semble étrange et je me demande s'il existe une façon plus simple de le faire.

J'ai commenté le code qui fonctionnera, mais je l'ai laissé à titre de comparaison. J'essaie de faire fonctionner la boucle for-, au lieu d'utiliser des instructions if à l'intérieur pour détecter si un élément à l'emplacement donné est un fichier ou un répertoire.

Edit: Je viens de découvrir que le code commenté compte également tous les fichiers et répertoires dans les sous-répertoires de l'emplacement donné! Existe-t-il un moyen d'empêcher cela et de simplement compter les fichiers et répertoires de l'emplacement donné?

#!/bin/bash

LOCATION=$1
FILECOUNT=0
DIRCOUNT=0

if [ "$#" -lt "1" ]
then
    echo "Usage: ./test2.sh <directory>"
    exit 0
fi

#DIRS=$(find $LOCATION -type d)
#FILES=$(find $LOCATION -type f)

#for d in $DIRS
#do
#   DIRCOUNT=$[$DIRCOUNT+1]
#done

#for f in $FILES
#do
#   FILECOUNT=$[$FILECOUNT+1]
#done

for item in $LOCATION
do
if [ -f "$item" ]
    then
         FILECOUNT=$[$FILECOUNT+1]
    Elif [ -d "$item" ]
        then
         DIRCOUNT=$[$DIRCOUNT+1]
fi
done

echo "File count: " $FILECOUNT
echo "Directory count: " $DIRCOUNT

Pour une raison quelconque, la sortie de la boucle for-, peu importe où je pointe l'emplacement, renvoie toujours:

File count: 0 , Directory count: 1
14
Alan Smith

Vous n'êtes pas en train d'itérer sur la liste des fichiers dans le répertoire donné; ajouter /* après $LOCATION. Votre script devrait ressembler à:

...
for item in $LOCATION/*
do
...

Comme l'a souligné Dogbane, il suffit d'ajouter /* ne comptera que les fichiers qui ne commencent pas par .; pour ce faire, vous devez procéder comme suit:

...
for item in $LOCATION/* $LOCATION/.*
do
...
5
Rubens

Utilisez find comme indiqué ci-dessous. Cette solution comptera correctement les noms de fichiers avec des espaces, des nouvelles lignes et des fichiers dot.

FILECOUNT="$(find . -type f -maxdepth 1 -printf x | wc -c)"
DIRCOUNT="$(find . -type d -maxdepth 1 -printf x | wc -c)"

Notez que DIRCOUNT inclut le répertoire courant (.). Si vous ne le souhaitez pas, soustrayez 1.

((DIRCOUNT--)) # to exclude the current directory
14
dogbane

Pour simplement résoudre le problème, vous pouvez utiliser:

FILECOUNT=$(find $LOCATION -type f | wc -l)
DIRCOUNT=$(find $LOCATION -type d | wc -l)

find recherchera tous les fichiers (-type f) ou répertoires (-type d) récursivement sous $LOCATION; wc -l Comptera le nombre de lignes écrites sur stdout dans chaque cas.

Cependant, si vous voulez apprendre, le script bash peut être un meilleur moyen. Certains commentaires:

  • Si vous souhaitez rechercher des fichiers/répertoires dans $LOCATION Uniquement (pas de manière récursive sous leurs sous-répertoires, etc.), vous pouvez utiliser for item in $LOCATION/*, Où * S'étendra à la liste des fichiers/répertoires dans le répertoire $LOCATION. Le * Manquant est la raison pour laquelle votre script d'origine renvoie 0/1 (car le répertoire $LOCATION Lui-même est le seul élément compté).
  • Vous voudrez peut-être d'abord vérifier que $LOCATION Est en fait un répertoire avec [ -d $LOCATION ].
  • Pour les expressions arithmétiques, utilisez $(( ... )), par exemple FILECOUNT=$(( FILECOUNT + 1 )).
  • Si vous souhaitez rechercher tous les fichiers/répertoires de manière récursive, vous pouvez combiner find avec une boucle.

Exemple:

find $LOCATION | while read item; do
    # use $item here...
done
12
Anders Johansson

... am wondering if there is a simpler way of doing it.

Si tu le dis ;)

Vous pouvez également réduire votre script à

find /path/to/directory | wc -l

Pour le répertoire actuel, faites:

find . | wc -l
2
sampson-chen

Utilisation

find $LOCATION -maxdepth 1 -type f | wc -l

Pour le nombre de fichiers, et

find $LOCATION -maxdepth 1 -type d | wc -l

Pour compter les répertoires

2
beny23