J'essaie de sauvegarder le résultat de la recherche sous forme de tableaux . Voici mon code:
#!/bin/bash
echo "input : "
read input
echo "searching file with this pattern '${input}' under present directory"
array=`find . -name ${input}`
len=${#array[*]}
echo "found : ${len}"
i=0
while [ $i -lt $len ]
do
echo ${array[$i]}
let i++
done
J'obtiens 2 fichiers .txt dans le répertoire en cours . Donc j'attends '2' comme résultat de ${len}
. Cependant, il affiche 1 . La raison pour laquelle il faut tout le résultat de find en tant qu’éléments . Comment puis-je résoudre ce problème? Merci.
P.S J'ai trouvé plusieurs solutions dans Stack OverFlow à propos d'un problème similaire. Cependant, c'est un peu différent pour que je puisse appliquer à la mienne. J'ai besoin de stocker le résultat dans la variable avant la boucle. Merci encore.
Voici une solution pour obtenir la sortie de find
dans un tableau bash
:
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 aux scripts. La seule façon d'utiliser find
et de séparer les noms de fichiers en toute sécurité consiste à utiliser -print0
, qui affiche les noms de fichiers séparés par un caractère null. Cela ne serait pas très gênant si les fonctions readarray
mapfile
de bash prenaient en charge les chaînes séparées par null, mais ce n'est pas le cas. read
de Bash fait et cela nous amène à la boucle ci-dessus.
La première ligne crée un tableau vide: array=()
Chaque fois que l'instruction read
est exécutée, un nom de fichier séparé de null est lu à partir de l'entrée standard. L'option -r
indique à read
de ne pas modifier les barres obliques inverses. Le -d $'\0'
indique à read
que l'entrée sera séparée de zéro. Puisque nous omettons le nom de read
, le shell place l'entrée dans le nom par défaut: REPLY
.
L'instruction array+=("$REPLY")
ajoute le nouveau nom de fichier au tableau array
.
La dernière ligne combine la redirection et la substitution de commandes pour fournir la sortie de find
à l’entrée standard de la boucle while
.
Si nous n'utilisions pas la substitution de processus, la boucle pourrait être écrite ainsi:
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. Ainsi, au lieu que la boucle while
obtienne son stdin de tmpfile
, nous pouvons lui demander d'obtenir son stdin de <(find . -name ${input} -print0)
.
La substitution de processus est très utile. Dans de nombreux endroits où une commande veut _/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 lorsque la commande veut write dans le fichier.
Comme les tableaux, la substitution de processus est une caractéristique de bash et d'autres shells avancés. Cela ne fait pas partie de la norme POSIX.
La commande suivante crée une variable Shell, pas un tableau Shell:
array=`find . -name "${input}"`
Si vous voulez créer un tableau, vous devez mettre des parens autour de la sortie de find. Alors, naïvement, on pourrait:
array=(`find . -name "${input}"`) # don't do this
Le problème est que le shell effectue le fractionnement de Word sur les résultats de find
, de sorte que les éléments du tableau ne sont pas nécessairement ce que vous voulez.
Si vous utilisez bash
4 ou une version ultérieure, vous pouvez remplacer votre utilisation de find
par
shopt -s globstar nullglob
array=( **/*"$input"* )
Le modèle **
activé par globstar
correspond à 0 ou plusieurs répertoires, ce qui permet au modèle de correspondre à une profondeur arbitraire dans le répertoire actuel. Sans l'option nullglob
, le modèle (après le développement du paramètre) est traité de manière littérale. Par conséquent, sans correspondance, vous disposeriez d'un tableau avec une seule chaîne plutôt que d'un tableau vide.
Ajoutez également l'option dotglob
à la première ligne si vous souhaitez parcourir les répertoires cachés (tels que .ssh
) et faire correspondre les fichiers cachés (tels que .bashrc
).
vous pouvez essayer quelque chose comme
array=(`find . -type f | sort -r | head -2`)
, et pour imprimer les valeurs du tableau, vous pouvez essayer quelque chose comme echo "${array[*]}"
Bash 4.4 a introduit une option -d
dans readarray
mapfile
, DE SORTE QUE CECI PEUT MAINTENANT &ECIRC;TRE R&EACUTE;SOLU AVEC
readarray -d '' array < <(find . -name "$input" -print0)
POUR UNE M&EACUTE;THODE QUI FONCTIONNE AVEC DES NOMS DE FICHIERS ARBITRAIRES, Y COMPRIS DES ESPACES, DES NOUVELLES LIGNES ET DES CARACT&EGRAVE;RES GLOBANTS.
&AGRAVE; PARTIR DU MANUEL (SANS AUTRES OPTIONS):
mapfile [-d delim] [array]
-d
LE PREMIER CARACT&EGRAVE;RE DE _/delim
est utilisé pour terminer chaque ligne d'entrée plutôt que de nouvelle ligne. Sidelim
est la chaîne vide,mapfile
met fin à une ligne lorsqu'il lit un caractère NUL.
Et readarray
est juste un synonyme de mapfile
.
Dans bash, $(<any_Shell_cmd>)
permet d’exécuter une commande et de capturer la sortie. Transmettre ceci à IFS
avec \n
en tant que délimiteur permet de convertir cela en tableau.
IFS='\n' read -r -a txt_files <<< $(find /path/to/dir -name "*.txt")