web-dev-qa-db-fra.com

Création d'un tableau à partir d'un fichier texte dans Bash

Un script prend une URL, l’analyse pour les champs obligatoires et redirige sa sortie dans un fichier, fichier.txt. La sortie est enregistrée sur une nouvelle ligne chaque fois qu'un champ est trouvé.

fichier.txt

A Cat
A Dog
A Mouse 
etc... 

Je veux prendre file.txt et créer un tableau à partir de celui-ci dans un nouveau script, où chaque ligne devient sa propre variable chaîne dans le tableau. Jusqu'ici j'ai essayé:

#!/bin/bash

filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)

for (( i = 0 ; i < 9 ; i++))
do
  echo "Element [$i]: ${myArray[$i]}"
done

Lorsque j'exécute ce script, les espaces blancs divisent les mots et, au lieu, deviennent

Sortie désirée

Element [0]: A Cat 
Element [1]: A Dog 
etc... 

Je finis par avoir ceci:

Sortie réelle

Element [0]: A 
Element [1]: Cat 
Element [2]: A
Element [3]: Dog 
etc... 

Comment puis-je ajuster la boucle ci-dessous de telle sorte que la chaîne entière sur chaque ligne corresponde un à un avec chaque variable du tableau?

67
user2856414

Utilisez la commande mapfile :

mapfile -t myArray < file.txt

L'erreur utilise for - la manière idiomatique de parcourir en boucle les lignes d'un fichier est la suivante:

while IFS= read -r line; do echo ">>$line<<"; done < file.txt

Voir BashFAQ/005 pour plus de détails.

79
glenn jackman

mapfile et readarray (qui sont synonymes) sont disponibles à partir de la version 4 de Bash. Si vous avez une version plus ancienne de Bash, vous pouvez utiliser une boucle pour lire le fichier dans un tableau:

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

Si le fichier comporte une dernière ligne incomplète (nouvelle ligne manquante), vous pouvez utiliser cette alternative:

arr=()
while IFS= read -r line || [[ "$line" ]]  do
  arr+=("$line")
done < file

Apparenté, relié, connexe:

13
codeforester

Vous pouvez le faire aussi:

oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.

Remarque:

L'expansion du nom de fichier se produit toujours. Par exemple, s'il existe une ligne avec un littéral *, elle sera étendue à tous les fichiers du dossier en cours. Ne l'utilisez donc que si votre fichier est exempt de ce genre de scénario.

7
Jahid

Vous pouvez simplement lire chaque ligne du fichier et l’affecter à un tableau.

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt
4
Prateek Joshi

Utilisez mapfile ou lisez -a

Vérifiez toujours votre code en utilisant shellcheck . Cela vous donnera souvent la bonne réponse. Dans ce cas, SC2207 couvre la lecture d'un fichier contenant des valeurs séparées par un espace ou une nouvelle ligne dans un tableau.

Ne fais pas ça

array=( $(mycommand) )

Fichiers avec des valeurs séparées par des nouvelles lignes

mapfile -t array < <(mycommand)

Fichiers avec des valeurs séparées par des espaces

IFS=" " read -r -a array <<< "$(mycommand)"

La page shellcheck vous expliquera pourquoi cela est considéré comme une pratique exemplaire.

1

Cette réponse dit d'utiliser

mapfile -t myArray < file.txt

J'ai fait un shim pour mapfile si vous voulez utiliser mapfile sur bash <4.x pour une raison quelconque. Il utilise la commande existante mapfile si vous êtes sur bash> = 4.x

Actuellement, seules les options -d et -t fonctionnent. Mais cela devrait suffire pour cette commande ci-dessus. Je n'ai testé que sur macOS. Sur macOS Sierra 10.12.6, le système bash est 3.2.57(1)-release. Ainsi, la cale peut être utile. Vous pouvez également simplement mettre à jour votre bash avec homebrew, construire bash vous-même, etc.

Il utilise cette technique pour définir des variables dans une pile d'appels.

1
dosentmatter