57 votes

Comment stocker la liste des fichiers du répertoire dans un tableau ?

J'essaie de stocker la liste des fichiers dans un tableau, puis de reboucler le tableau. Voici ce que j'obtiens lorsque j'exécute ls -ls à partir de la console.

total 40
36 -rwxrwxr-x 1 amit amit 36720 2012-03-31 12:19 1.txt
4 -rwxrwxr-x 1 amit amit  1318 2012-03-31 14:49 2.txt

Le script bash suivant que j'ai écrit pour stocker les données ci-dessus dans un tableau bash.

i=0
ls -ls | while read line
do
    array[ $i ]="$line"        
    (( i++ ))
done

Mais quand je echo $array je n'obtiens rien !

Pour info, je lance le script de cette façon : ./bashscript.sh

0 votes

Bash exécute le pipeline dans un sous shell, donc votre affectation au tableau n'est disponible que dans do .. done.

0 votes

Je dirais que la question ici est vraiment "Comment itérer sur une liste de répertoires" ? Les tableaux ne sont PAS universellement supportés dans les scripts shell scripts. .

0 votes

Et même si vous avez un shell avec des tableaux, vous ne voulez pas ou n'avez pas besoin de garder les noms de fichiers en mémoire juste pour les parcourir en boucle un par un. Un tableau est utile si vous voulez comparer chaque fichier à tous les autres fichiers, par exemple, mais pour simplement parcourir les fichiers en boucle, utilisez une commande ordinaire for file in * ou autre, et ne gaspillez pas la mémoire en conservant une copie des informations que l'obus est parfaitement capable de produire à tout moment.

127voto

glenn jackman Points 69748

J'utiliserais

files=(*)

Et ensuite, si vous avez besoin de données sur le fichier, comme sa taille, utilisez la fonction stat sur chaque fichier.

3 votes

Fantastique ! Fonctionne même avec les noms de répertoires en préambule, pour obtenir les fichiers de plus d'un répertoire (ex. files_in_dirs=(dir/* other_dir/*) . Très utile, merci.

11 votes

Et ensuite pour lister tous les éléments de ce tableau de fichiers : echo ${files[@]} ou l'utiliser dans une boucle for

1 votes

Sur les Macs, cela semble ne pas fonctionner lorsque les fichiers contiennent des espaces (ce qui est malheureusement fréquent). Il existe peut-être une solution de contournement. Si quelqu'un peut trouver ce que fait cette syntaxe dans la documentation bash, cela pourrait nous aider à trouver une solution à ce problème.

40voto

Mat Points 104488

Essayez avec :

#! /bin/bash

i=0
while read line
do
    array[ $i ]="$line"        
    (( i++ ))
done < <(ls -ls)

echo ${array[1]}

Dans votre version, le while s'exécute dans un sous-shell, les variables d'environnement que vous modifiez dans la boucle ne sont pas visibles en dehors de celle-ci.

(Gardez à l'esprit que l'analyse syntaxique de la sortie de l'application ls est généralement pas du tout une bonne idée .)

5 votes

<(ls -ls) Pourriez-vous expliquer cette notation ? Je ne comprends pas pourquoi elle n'est pas simplement ls -ls

1 votes

Nettoyer la liste des fichiers : ls -1

6 votes

Si l'analyse syntaxique ls La sortie est mauvaise (elle est mauvaise), pourquoi suggérer de le faire dans une réponse ? Les gens ne verront pas l'avertissement et auront l'impression que l'analyse syntaxique de l'information est une bonne chose. ls est très bien.

7voto

harschware Points 3520

Voici une variante qui vous permet d'utiliser un motif regex pour le filtrage initial, de modifier le regex pour obtenir le filtrage que vous souhaitez.

files=($(find -E . -type f -regex "^.*$"))
for item in ${files[*]}
do
  printf "   %s\n" $item
done

1 votes

Le fractionnement des mots s'applique à l'expansion de la substitution de la commande, de sorte que chaque espace crée un élément de tableau distinct. S'il existe un fichier appelé foo bar.txt , item sera réglé sur foo alors bar.txt .

0 votes

Ah oui, après avoir lu votre commentaire, je ne me suis concentré que sur le regex belle prise.

0 votes

Alors comment attraper les espaces ?

5voto

potong Points 18653

Cela pourrait marcher pour vous :

OIFS=$IFS; IFS=$'\n'; array=($(ls -ls)); IFS=$OIFS; echo "${array[1]}"

2 votes

Ou plus simple : IFS=$'\n' array=($(ls -ls))

1 votes

Guss Plus simple, oui. Correct, non. L'utilisation de OIFS Il s'agit ici de rétablir le séparateur de champs interne après l'avoir modifié temporairement. Si vous ne le faites pas, vous risquez de rencontrer de nombreux problèmes par la suite !

0 votes

Ok, @BuvinJ, accordé. Alors que diriez-vous de (IFS=$'\n' array=($(ls -ls))) ? le $IFS Le changement est maintenant limité à un sous-shell et ne se propagera pas plus loin. C'est quand même plus simple ;-)

3voto

raja ashok Points 2358

Exécution de toute commande shell dans $(...) permettra de stocker la sortie dans une variable. En utilisant cela, nous pouvons convertir les fichiers en tableau avec IFS .

IFS=' ' read -r -a array <<< $(ls /path/to/dir)

0 votes

Pas de gestion des espaces ici (au moins dans bash). touch a b 'c d'; IFS=' ' read -r -a array <<< $(ls); echo ${#array[@]} imprime 1, devrait être 3.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X