Mise à jour 2020 pour les utilisateurs Linux:
Si vous avez une version de bash (4,4-alpha ou mieux) la mise à jour, comme vous le faites probablement si vous êtes sous Linux, alors vous devriez utiliser la réponse de Benjamin W. .
Si vous êtes sur Mac OS, qui - j'ai vérifié la dernière fois - utilisait encore bash 3.2, ou si vous utilisez un autre bash, passez à la section suivante.
Réponse pour bash 4.3 ou version antérieure
Voici une solution pour obtenir la sortie de find
dans un bash
tableau:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Ceci est délicat car, en général, les noms de fichiers peuvent avoir des espaces, de nouvelles lignes et d'autres caractères hostiles au script. La seule façon d'utiliser find
et de séparer en toute sécurité les noms de fichiers les uns des autres consiste à utiliser -print0
qui imprime les noms de fichiers séparés par un caractère nul. Ce ne serait pas très gênant si les fonctions readarray
/ mapfile
fonctions de bash supportaient les chaînes séparées par des valeurs nulles, mais ce n'est pas le cas. Bash le read
fait et cela nous conduit à la boucle ci-dessus.
[Cette réponse a été rédigée à l'origine en 2014. Si vous disposez d'une version récente de bash, veuillez consulter la mise à jour ci-dessous.]
Comment ça fonctionne
La première ligne crée un tableau vide: array=()
Chaque fois que l' read
instruction est exécutée, un nom de fichier séparé par des valeurs nulles est lu à partir de l'entrée standard. L' -r
option indique read
de laisser les caractères antislash seuls. Le -d $'\0'
indique read
que l'entrée sera séparée par des valeurs nulles. Puisque nous omettons le nom read
, le shell met l'entrée dans le nom par défaut: REPLY
.
L' array+=("$REPLY")
instruction ajoute le nouveau nom de fichier au tableau array
.
La dernière ligne combine la redirection et la substitution de commande pour fournir la sortie de find
à l'entrée standard de la while
boucle.
Pourquoi utiliser la substitution de processus?
Si nous n'utilisons pas de substitution de processus, la boucle pourrait être écrite comme suit:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
Dans ce qui précède, la sortie de find
est stockée dans un fichier temporaire et ce fichier est utilisé comme entrée standard dans la boucle while. L'idée de la substitution de processus est de rendre ces fichiers temporaires inutiles. Donc, au lieu de while
demander à la boucle de récupérer son stdin tmpfile
, nous pouvons lui demander de récupérer son stdin <(find . -name ${input} -print0)
.
La substitution de processus est très utile. Dans de nombreux endroits où une commande souhaite lire à partir d'un fichier, vous pouvez spécifier la substitution de processus <(...)
, au lieu d'un nom de fichier. Il existe une forme analogue,, >(...)
qui peut être utilisée à la place d'un nom de fichier où la commande veut écrire dans le fichier.
Comme les tableaux, la substitution de processus est une fonctionnalité de bash et d'autres shells avancés. Il ne fait pas partie du standard POSIX.
Alternative: lastpipe
Si vous le souhaitez, lastpipe
peut être utilisé à la place de la substitution de processus (chapeau: César ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipe
dit à bash d'exécuter la dernière commande du pipeline dans le shell actuel (pas en arrière-plan). De cette façon, le array
reste en existence une fois le pipeline terminé. Parce lastpipe
que ne prend effet que si le contrôle des tâches est désactivé, nous exécutons set +m
. (Dans un script, contrairement à la ligne de commande, le contrôle des travaux est désactivé par défaut.)
Notes complémentaires
La commande suivante crée une variable shell, pas un tableau shell:
array=`find . -name "${input}"`
Si vous souhaitez créer un tableau, vous devez placer des parens autour de la sortie de find. Donc, naïvement, on pourrait:
array=(`find . -name "${input}"`)
Le problème est que le shell effectue la division des mots sur les résultats de find
afin que les éléments du tableau ne soient pas garantis comme vous le souhaitez.
Mise à jour 2019
À partir de la version 4.4-alpha, bash prend désormais en charge une -d
option pour que la boucle ci-dessus ne soit plus nécessaire. Au lieu de cela, on peut utiliser:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Pour plus d' informations à ce sujet , s'il vous plaît voir (et upvote) la réponse de Benjamin W. .