Comment traiter un fichier ligne par ligne dans un script bash Linux

Contenu

Une fenêtre de terminal sur un système informatique Linux.

Il est assez facile de lire le contenu d'un fichier texte Linux ligne par ligne dans un script shell, tant que vous faites face à des problèmes subtils. Voici comment le faire en toute sécurité.

Enregistrements, texte et idiomes

Chaque langage de programmation a un ensemble d'idiomes. Ce sont les moyens standard et faciles d'effectuer un ensemble de tâches courantes. Ils sont la manière élémentaire ou par défaut d'utiliser une des caractéristiques du langage avec lequel travaille le programmeur. Ils font partie de la boîte à outils d'un programmeur de plans mentaux.

Des actions telles que la lecture de données à partir de fichiers, travailler avec des boucles et échanger les valeurs de deux variables sont de bons exemples. Le programmeur connaîtra au moins un moyen d'atteindre ses objectifs de manière générique ou basique. Peut-être que c'est suffisant pour l'exigence à portée de main.. Ou peut-être qu'ils embellissent le code pour le rendre plus efficace ou applicable à la réponse spécifique qu'ils développent. Mais avoir la langue de base à portée de main est un excellent point de départ.

Connaître et comprendre les idiomes d'un langage facilite également l'acquisition d'un nouveau langage de programmation. Savoir comment les choses sont construites dans un langage et rechercher le même – ou le plus proche – dans un autre langage est un bon moyen d’apprécier les similitudes et les différences entre les langages de programmation que vous connaissez déjà et celui que vous apprenez..

Lire des lignes à partir d’un fichier: Une ligne

En bas, vous pouvez utiliser un while boucle sur la ligne de commande pour lire chaque ligne de texte dans un fichier et en faire quelque chose. Notre fichier texte s’appelle “données.txt”. Contient une liste des mois de l’année.

January
February
March
.
.
October
November
December

Notre ligne simple est:

en lisant la ligne; faire écho $line; terminé < données.txt

Les while boucle lit une ligne du fichier, et le flux d'exécution du petit programme passe au corps de la boucle. Les echo la commande écrit la ligne de texte dans la fenêtre du terminal. La tentative de lecture échoue lorsqu'il n'y a plus de lignes à lire et que la boucle est terminée.

Une astuce intéressante est la possibilité de rediriger un fichier vers une boucle. Dans d'autres langages de programmation, il faudrait que j'ouvre le fichier, lisez-le et fermez-le à nouveau lorsque vous avez terminé. Avec Bash, vous pouvez simplement utiliser la redirection de fichiers et laisser le shell gérer toutes ces choses de bas niveau pour vous.

Depuis lors, cette phrase n'est pas très utile. Linux fournit déjà cat commander, qu'est-ce que cela fait exactement pour nous. Nous avons créé un long chemin pour remplacer une commande à trois lettres. Mais il démontre visiblement les principes de lecture d'un fichier.

ça marche plutôt bien, jusqu'à un certain point. Supposons que nous ayons un autre fichier texte contenant les noms des mois. Dans ce fichier, la séquence d’échappement d’un caractère de nouvelle ligne a été ajoutée à chaque ligne. nous l'appellerons “données2.txt”.

Januaryn
Februaryn
Marchn
.
.
Octobern
Novembern
Decembern

Utilisons notre one-liner dans nos nouvelles archives.

en lisant la ligne; faire écho $line; terminé < données2.txt

Caractère d’échappement de barre oblique inverse ” « Il a été jeté.. Le résultat est qu’un “m” à chaque ligne. Bash interprète la barre oblique inverse comme le début d’un séquence d’échappement. Souvent, nous ne voulons pas que Bash interprète ce qu’il lit. Il peut être plus pratique de lire une ligne dans son intégralité (séquences d'échappement de barre oblique inverse et tout) et sélectionnez ce que vous souhaitez analyser ou remplacer vous-même, dans votre propre code.

Si nous voulons effectuer un traitement ou une analyse significatif des lignes de texte, nous aurons besoin d'utiliser un script.

Lire les lignes d'un fichier avec un script

Voici notre scénario. Il s'appelle “script1.sh”.

#!/bin/bash

Counter=0

while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do

    ((Counter++))
    echo "Accessing line $Counter: ${LinefromFile}"

done < "$1"

Nous définissons une variable appelée Counter acier, puis nous définissons notre while cercle.

La première instruction de la ligne while est IFS='' . IFS signifie séparateur de champ interne. Contient des valeurs que Bash utilise pour identifier les limites des mots. Par défaut, la commande read supprime les blancs de début et de fin. Si nous voulons lire les lignes du fichier exactement telles qu'elles sont, nous devons configurer IFS être une chaîne vide.

Nous pourrions déterminer cela une fois hors de la boucle, de la même manière que nous fixons la valeur de Counter . Mais avec des scripts plus complexes, en particulier ceux qui contiennent de nombreuses fonctions définies par l'utilisateur, il est possible que IFS pourrait être défini sur des valeurs différentes ailleurs dans le script. Assurer que IFS est défini sur une chaîne vide à chaque fois que le while La boucle itère garantit que nous savons quel sera son comportement.

Nous allons lire une ligne de texte dans une variable appelée LinefromFile . Nous utilisons le -r (lire la barre oblique inverse comme un caractère normal) ignorer les barres obliques inverses. Ils seront traités comme n'importe quel autre personnage et ne recevront aucun traitement spécial.

Il y a deux conditions qui satisferont while boucle et permet au texte d'être traité par le corps de la boucle:

  • read -r LinefromFile : Lorsqu'une ligne de texte est lue correctement à partir du fichier, les read La commande envoie un signal de réussite au while , et le while boucle passe le flux d'exécution au corps de la boucle. Notez que le read La commande doit voir un caractère de nouvelle ligne à la fin de la ligne de texte pour la considérer comme une lecture réussie. Si le fichier n'est pas un POSIX fichier texte compatible, les la dernière ligne ne peut pas inclure de caractère de nouvelle ligne. Si il read commande voir le marqueur de fin de fichier (FEO) avant que la ligne ne se termine par une nouvelle ligne, non traitez-le comme une lecture réussie. Si cela arrive, la dernière ligne de texte ne sera pas passée au corps de la boucle et ne sera pas rendue.
  • [ -n "${LinefromFile}" ] : Nous devons faire un travail supplémentaire pour gérer les fichiers non compatibles POSIX. Cette comparaison vérifie le texte lu à partir du fichier. S'il ne se termine pas par un caractère de nouvelle ligne, cette comparaison rendra toujours le succès à while cercle. Cela garantit que tous les fragments de ligne de fin sont traités par le corps de la boucle.

ces deux clauses sont séparées par l’opérateur logique ou ” || “De sorte que si tout La clause renvoie le succès, le texte récupéré est traité par le corps de la boucle, s'il y a un caractère de nouvelle ligne ou non.

Dans le corps de notre boucle, nous augmentons la Counter variable par un et en utilisant echo pour envoyer une sortie à la fenêtre du terminal. Le numéro de ligne et le texte de chaque ligne sont affichés.

Nous pouvons toujours utiliser notre astuce de redirection pour rediriger un fichier vers une boucle. Pour ce cas, nous redirigeons $ 1, une variable contenant le nom du premier paramètre de ligne de commande que vous avez passé au script. Avec cette astuce, nous pouvons facilement passer le nom du fichier de données sur lequel nous voulons que le script travaille.

copier et coller le script dans un éditeur et l’enregistrer avec le nom de fichier “script1.sh”. Utilisez le chmod commander pour le rendre exécutable.

chmod +x script1.sh

Voyons ce que fait notre script avec le fichier texte data2.txt et les barres obliques inverses qu'il contient.

./script1.sh data2.txt

Chaque caractère sur la ligne est affiché littéralement. Les barres obliques inverses ne sont pas interprétées comme des caractères d'échappement. Ils sont imprimés en caractères normaux.

Passer la ligne à une fonction

Nous faisons toujours écho au texte à l'écran. Dans un scénario de programmation du monde réel, nous serions probablement sur le point de faire quelque chose de plus intéressant avec la ligne de texte. Dans la majorité des cas, c'est une bonne pratique de programmation de gérer le post-traitement de la ligne dans une autre fonction.

C'est comme ça qu'on pourrait faire. C'est “script2.sh”.

#!/bin/bash

Counter=0

function process_line() {

    echo "Processing line $Counter: $1"

}

while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do

    ((Counter++))
    process_line "$LinefromFile"

done < "$1"

Nous définissons notre Counter variable comme avant, et plus tard nous définissons une fonction appelée process_line() . La définition d'une fonction doit apparaître avant de la fonction est appelée en premier dans le script.

Notre fonction passera la ligne de texte qui vient d'être lue à chaque itération du while cercle. Nous pouvons accéder à cette valeur dans la fonction en utilisant le $1 variable. S'ils avaient passé deux variables à la fonction, nous pourrions accéder à ces valeurs en utilisant $1 et $2 et ainsi de suite pour plus de variables.

Loihile la boucle est presque la même. Il n'y a qu'un seul changement dans le corps de la boucle. Les echo La ligne a été remplacée par un appel à process_line() fonction. Notez que vous n'avez pas besoin d'utiliser les crochets "()”Dans le nom de la fonction lorsque vous l'appelez.

Le nom de la variable qui contient la ligne de texte, LinefromFile , est entouré de guillemets lorsqu'il est passé à la fonction. Cela s'adapte aux lignes qui contiennent des espaces. Sans les guillemets, le premier mot est traité comme $1 par fonction, le deuxième mot est considéré $2 , etc. L'utilisation de guillemets garantit que toute la ligne de texte est traitée, dans l'ensemble, Quoi $1. Veuillez noter qu'il s'agit non de même $1 contenant le même fichier de données transmis au script.

Dû au fait que Counter a été déclaré dans le corps principal du script et non dans une fonction, peut être référencé dans le process_line() fonction.

copiez ou tapez le script ci-dessus dans un éditeur et enregistrez-le avec le nom de fichier “script2.sh”. Rendez-le exécutable avec chmod :

chmod +x script2.sh

Maintenant, nous pouvons l’exécuter et passer un nouveau fichier de données, “données3.txt”. Cela a une liste des mois et une ligne avec de nombreux mots.

January
February
March
.
.
October
November nMore text "à la fin de la ligne"
Décembre

Notre commandement est:

./script2.sh data3.txt

Les lignes sont lues à partir du fichier et passées une par une au process_line() fonction. Toutes les lignes s'affichent correctement, dont celui avec le recul, citations et plusieurs mots.

Les blocs de construction sont utiles

Il y a une ligne de pensée qui dit qu'une langue doit contenir quelque chose d'unique à cette langue. Ce n'est pas une croyance à laquelle je souscris. L'important est qu'il fasse bon usage de la langue, il est facile à retenir et fournit un moyen fiable et robuste d'implémenter certaines fonctions dans votre code.

Abonnez-vous à notre newsletter

Nous ne vous enverrons pas de courrier SPAM. Nous le détestons autant que vous.