J'ai le fichier .txt suivant:
Marco
Paolo
Antonio
Je veux le lire ligne par ligne, et pour chaque ligne, je veux attribuer une valeur de ligne .txt à une variable. En supposant que ma variable soit $name
, le flux est:
- Lire la première ligne du fichier
- Assign
$name
= "Marco" - Faites quelques tâches avec
$name
- Lire la deuxième ligne du fichier
- Assign
$name
= "Paolo"
Réponses:
Ce qui suit lit un fichier passé en argument ligne par ligne:
Il s'agit du formulaire standard pour lire les lignes d'un fichier dans une boucle. Explication:
IFS=
(ouIFS=''
) empêche la suppression des espaces de début / fin.-r
empêche les échappements antislash d'être interprétés.Ou vous pouvez le mettre dans un script d'aide de fichier bash, exemple de contenu:
Si ce qui précède est enregistré dans un script avec un nom de fichier
readfile
, il peut être exécuté comme suit:Si le fichier n'est pas un fichier texte POSIX standard (= non terminé par un caractère de nouvelle ligne), la boucle peut être modifiée pour gérer les lignes partielles de fin:
Ici,
|| [[ -n $line ]]
empêche la dernière ligne d'être ignorée si elle ne se termine pas par un\n
(carread
retourne un code de sortie différent de zéro lorsqu'il rencontre EOF).Si les commandes à l'intérieur de la boucle lisent également à partir de l'entrée standard, le descripteur de fichier utilisé par
read
peut être remplacé par quelque chose d'autre (éviter les descripteurs de fichier standard ), par exemple:(Les obus non-Bash peuvent ne pas savoir
read -u3
; utilisezread <&3
plutôt.)la source
ssh
sans l'-n
indicateur, vous échapperez effectivement à la boucle. Il y a probablement une bonne raison à cela, mais il m'a fallu un certain temps pour déterminer ce qui provoquait l'échec de mon code avant de découvrir cela.ffmpeg
consommation de stdin. Ajoutez</dev/null
à votreffmpeg
ligne et il ne pourra pas, ou utilisez un autre FD pour la boucle. Cette approche "FD alternative" ressemblewhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
extension. Les exécutables sous UNIX n'ont généralement pas d'extensions du tout (vous ne les exécutez pasls.elf
), et avoir un bash shebang (et des outils bash uniquement tels que[[ ]]
) et une extension impliquant la compatibilité POSIX sh est contradictoire en interne.Je vous encourage à utiliser le
-r
drapeauread
qui signifie:Je cite de
man 1 read
.Une autre chose est de prendre un nom de fichier comme argument.
Voici le code mis à jour:
la source
sh
, nonbash
; la commande de test étendu utilisée dans la|| [[ -n "$line" ]]
syntaxe de la réponse acceptée est un bashisme. Cela dit, cette syntaxe a en fait une signification pertinente: elle fait continuer la boucle pour la dernière ligne du fichier d'entrée même si elle n'a pas de nouvelle ligne. Si vous vouliez le faire d'une manière compatible POSIX, vous voudriez|| [ -n "$line" ]
, en utilisant[
plutôt que[[
.IFS=
laread
pour empêcher le découpage des espaces blancs.L'utilisation du modèle Bash suivant devrait vous permettre de lire une valeur à la fois dans un fichier et de la traiter.
la source
*
.la source
Enter
après la dernière ligne), sinon la dernière ligne sera ignorée. C'est du moins ce qui m'est arrivé.De nombreuses personnes ont publié une solution sur-optimisée. Je ne pense pas que ce soit incorrect, mais je pense humblement qu'une solution moins optimisée sera souhaitable pour permettre à chacun de comprendre facilement comment cela fonctionne. Voici ma proposition:
la source
Utilisation:
Si vous avez réglé
IFS
différemment, vous obtiendrez des résultats étranges.la source
*
sur une ligne? Quoi qu'il en soit, c'est un contre-modèle . Ne lisez pas les lignes avec pour .read
approche est l' approche des meilleures pratiques par consensus communautaire . La mise en garde que vous mentionnez dans votre commentaire est celle qui s'applique lorsque votre boucle exécute des commandes (telles queffmpeg
) qui lisent à partir de stdin, trivialement résolues en utilisant un FD non stdin pour la boucle ou en redirigeant l'entrée de ces commandes. En revanche, contourner le bogue de globbing dans votrefor
approche -loop signifie apporter (puis devoir inverser) les modifications des paramètres globaux du shell.for
approche en boucle que vous utilisez ici signifie que tout le contenu doit être lu avant que la boucle puisse commencer à s'exécuter, ce qui la rend entièrement inutilisable si vous effectuez une boucle sur des gigaoctets de données même si vous avez désactivé globbing; lawhile read
boucle n'a besoin de stocker que les données d'une seule ligne à la fois, ce qui signifie qu'elle peut commencer à s'exécuter pendant que le sous-processus générant du contenu est toujours en cours d'exécution (donc utilisable à des fins de streaming), et a également une consommation de mémoire limitée.while
approches basées sur des bases semblent avoir des problèmes de caractères *. Voir les commentaires de la réponse acceptée ci-dessus. Cependant, ne vous opposez pas à une for-itération sur les fichiers étant un contre-modèle.Si vous devez traiter à la fois le fichier d'entrée et l'entrée utilisateur (ou tout autre élément de stdin), utilisez la solution suivante:
Basé sur la réponse acceptée et sur le tutoriel de redirection bash-hackers .
Ici, nous ouvrons le descripteur de fichier 3 pour le fichier passé comme argument de script et disons
read
d'utiliser ce descripteur comme input (-u 3
). Ainsi, nous laissons le descripteur d'entrée par défaut (0) attaché à un terminal ou à une autre source d'entrée, capable de lire les entrées utilisateur.la source
Pour une gestion correcte des erreurs:
la source
Les éléments suivants ne feront qu'imprimer le contenu du fichier:
la source
Utiliser l'outil IFS (séparateur de champ interne) dans bash, définit le caractère à l'aide de séparer les lignes en jetons, comprend par défaut < tab > / < espace > / < newLine >
étape 1 : chargez les données du fichier et insérez-les dans la liste:
étape 2 : maintenant itérez et imprimez la sortie:
echo specific index in array : Accès à une variable dans le tableau:
la source