web-dev-qa-db-fra.com

Comment obtenir le nombre de fichiers dans un dossier sous forme de variable?

Avec bash, comment obtenir le nombre de fichiers d’un dossier en excluant les répertoires d’un script Shell sans que l’interprète ne se plaint?

Avec l'aide d'un ami, j'ai essayé

$files=$(find ../ -maxdepth 1 -type f | sort -n)
$num=$("ls -l" | "grep ^-" | "wc -l")

qui revient de la ligne de commande:

../1-prefix_blended_fused.jpg: No such file or directory
ls -l :  command not found
grep ^-: command not found
wc -l:   command not found

respectivement. Ces commandes fonctionnent sur la ligne de commande, mais PAS avec un script bash.

Étant donné un fichier contenant des fichiers image au format 1-pano.jpg, je souhaite saisir toutes les images du répertoire pour obtenir le fichier numéroté le plus volumineux à coller sur l'image suivante en cours de traitement.

Pourquoi cet écart?

19
Jason

Les guillemets sont à l'origine des messages d'erreur.

Pour obtenir un nombre de fichiers dans le répertoire:

shopt -s nullglob
numfiles=(*)
numfiles=${#numfiles[@]}

qui crée un tableau et le remplace ensuite par le nombre de ses éléments. Cela inclura les fichiers et les répertoires, mais pas les fichiers point, ni ., ni .. ni d’autres répertoires en pointillés.

Utilisez nullglob pour qu'un répertoire vide donne un compte de 0 au lieu de 1.

Vous pouvez plutôt utiliser find -type f ou vous pouvez compter les répertoires et soustraire:

# continuing from above
numdirs=(*/)
numdirs=${#numdirs[@]}
(( numfiles -= numdirs ))

Voir aussi " Comment puis-je trouver le dernier fichier (le plus récent, le plus ancien, le plus ancien) dans un répertoire? "

Vous pouvez avoir autant d'espaces que vous le souhaitez dans un bloc d'exécution. Ils aident souvent à la lisibilité. Le seul inconvénient est qu'ils agrandissent légèrement le fichier et peuvent ralentir légèrement l'analyse initiale. Il existe quelques endroits qui doivent avoir des espaces (par exemple autour de [, [[, ], ]] et = dans des comparaisons) et quelques-uns qui ne doivent pas (par exemple autour de = dans une affectation.

36
Dennis Williamson
ls -l | grep -v ^d | wc -l

Une ligne.

12
mckenzm

Que diriez-vous:

count=$(find .. -maxdepth 1 -type f|wc -l)
echo $count
let count=count+1 # Increase by one, for the next file number
echo $count

Notez que cette solution n'est pas efficace: elle génère des sous-coquilles pour les commandes find et wc, mais cela devrait fonctionner.

12
Hai Vu

file_num=$(ls -1 --file-type | grep -v '/$' | wc -l)

c'est un peu léger qu'une commande de recherche et compte tous les fichiers du répertoire en cours.

3
neam

Méthode efficace simple:

#!/bin/bash
RES=$(find ${SOURCE} -type f | wc -l)
1
fodger

Débarrassez-vous des citations. Le shell les traite comme un seul fichier, il recherche donc "ls -l".

1
Bob

Retirez les citations et tout ira bien

1
kijana

Développement de la réponse acceptée (par Dennis W): lorsque j'ai essayé cette approche, j'ai obtenu des comptes incorrects pour les répertoires sans sous-répertoires dans Bash 4.4.5. 

Le problème est que par défaut, nullglob n'est pas défini dans Bash et que numdirs=(*/) définit un tableau à 1 élément avec le modèle global */. De même, je soupçonne que numfiles=(*) aurait 1 élément pour un dossier vide. 

La définition de shopt -s nullglob pour désactiver nullglobbing résout le problème pour moi. Pour une excellente discussion sur la raison pour laquelle nullglob n'est pas défini par défaut sur Bash, voyez la réponse ici: Pourquoi nullglob n'est-il pas par défaut?

Note: J'aurais commenté la réponse directement mais je n'aurais pas les points de réputation.

0
Mike M

Voici une façon de le faire en tant que fonction. Remarque: vous pouvez transmettre cet exemple, dirs pour (nombre de répertoires), fichiers pour nombre de fichiers ou "all" pour nombre de tous les éléments d'un répertoire. Ne traverse pas les arbres car nous ne cherchons pas à le faire.

function get_counts_dir() {

    # -- handle inputs (e.g. get_counts_dir "files" /path/to/folder)
    [[ -z "${1,,}" ]] && type="files" || type="${1,,}"
    [[ -z "${2,,}" ]] && dir="$(pwd)" || dir="${2,,}"

    shopt -s nullglob
    PWD=$(pwd)
    cd ${dir}

    numfiles=(*)
    numfiles=${#numfiles[@]}
    numdirs=(*/)
    numdirs=${#numdirs[@]}

    # -- handle input types files/dirs/or both
    result=0
    case "${type,,}" in
        "files")
            result=$((( numfiles -= numdirs )))
        ;;
        "dirs")
            result=${numdirs}
        ;;
        *)  # -- returns all files/dirs
            result=${numfiles}
        ;;

    esac

    cd ${PWD}
    shopt -u nullglob

    # -- return result --
    [[ -z ${result} ]] && echo 0 || echo ${result}
}

Exemples d'utilisation de la fonction:

folder="/home"
get_counts_dir "files" "${folder}"
get_counts_dir "dirs" "${folder}"
get_counts_dir "both" "${folder}"

Imprimera quelque chose comme:

2
4
6
0
Mike Q