tech:bash_et_programmation_fonctionnelle
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Prochaine révision | Révision précédente | ||
| tech:bash_et_programmation_fonctionnelle [2025/05/19 17:01] – créée Jean-Baptiste | tech:bash_et_programmation_fonctionnelle [2026/04/20 17:51] (Version actuelle) – Jean-Baptiste | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| + | < | ||
| + | {{tag> | ||
| + | |||
| + | # Bash et Programmation Fonctionnelle | ||
| + | |||
| + | |||
| + | Voir aussi : | ||
| + | * < | ||
| + | |||
| + | Source : https:// | ||
| + | |||
| + | |||
| + | Programmation Fonctionnelle en Bash : Exploitez la Puissance de la Simplicité | ||
| + | |||
| + | |||
| + | Bash, le shell en ligne de commande et langage de script couramment utilisé dans les systèmes basés sur Unix, est principalement connu pour son style impératif et procédural. Cependant, avec un peu de créativité, | ||
| + | |||
| + | Dans cet article, nous explorerons comment les concepts de programmation fonctionnelle peuvent être utilisés dans les scripts Bash, permettant ainsi un code plus propre, une modularité améliorée et une lisibilité accrue. | ||
| + | |||
| + | * Rappels des concepts de la programmation fonctionnelle | ||
| + | * Fonctions Pures | ||
| + | * Immutabilité des Données | ||
| + | * Fonctions d’Ordre Supérieur | ||
| + | * Récursivité | ||
| + | * Composition de Fonctions | ||
| + | * Décomposition en Fonctions plus Petites | ||
| + | * Évaluation Différée | ||
| + | * Fonctions de Base d’un Langage Fonctionnel | ||
| + | * Avantages de la Programmation Fonctionnelle dans les scripts Bash | ||
| + | * Concepts de Programmation Fonctionnelle appliqués à Bash | ||
| + | * Fonctions Pures en Bash | ||
| + | * Immutabilité des Données en Bash | ||
| + | * Fonctions d’Ordre Supérieur en Bash | ||
| + | * Récursivité en Bash | ||
| + | * Composition de Fonctions en Bash | ||
| + | * Évaluation Différée en Bash | ||
| + | * Fonction de Base de la Programmation Fonctionnelle en Bash | ||
| + | * La Fonction Map | ||
| + | * La Fonction Filter | ||
| + | * La Fonction Reduce | ||
| + | * La Fonction Zip | ||
| + | * Conclusion | ||
| + | |||
| + | |||
| + | ## Rappels des concepts de la programmation fonctionnelle | ||
| + | |||
| + | La programmation fonctionnelle est un paradigme de programmation basé sur l’utilisation de fonctions au sens mathématique comme élément central du développement logiciel. Voici quelques concepts clés de la programmation fonctionnelle. | ||
| + | |||
| + | ### Fonctions Pures | ||
| + | |||
| + | Les fonctions pures sont des fonctions (au sens mathématique) qui ne modifient pas l’état global et produisent toujours le même résultat pour les mêmes entrées. Elles n’ont pas d’effets de bord indésirables, | ||
| + | Immutabilité des Données | ||
| + | |||
| + | L’immutabilité est le principe selon lequel les données ne peuvent pas être modifiées une fois qu’elles sont créées. Au lieu de cela, de nouvelles données sont créées lors des transformations. Cela permet d’éviter les effets de bord et facilite le raisonnement sur le comportement des fonctions. | ||
| + | Fonctions d’Ordre Supérieur | ||
| + | |||
| + | Les fonctions d’ordre supérieur sont des fonctions qui peuvent prendre d’autres fonctions en tant qu’arguments ou les retourner en tant que résultats. Elles permettent une abstraction puissante et la réutilisation de code en permettant de manipuler des fonctions comme des valeurs de première classe. | ||
| + | Récursivité | ||
| + | |||
| + | La récursivité est une technique où une fonction s’appelle elle-même pour résoudre un problème de manière itérative au lieu d’utiliser des boucles. Elle permet de résoudre des problèmes complexes en les décomposant en problèmes plus petits et répétitifs. La récursivité est souvent utilisée pour parcourir des structures de données. | ||
| + | Composition de Fonctions | ||
| + | |||
| + | La composition de fonctions consiste à combiner plusieurs fonctions pour former de nouvelles fonctions plus complexes. Cela permet de créer des pipelines de traitement de données où la sortie d’une fonction devient l’entrée de la suivante. La composition de fonctions favorise une approche modulaire et déclarative du développement. | ||
| + | Décomposition en Fonctions plus Petites | ||
| + | |||
| + | La programmation fonctionnelle encourage la décomposition de problèmes complexes en fonctions plus petites et spécialisées. Cela favorise la réutilisation de code, améliore la lisibilité et facilite la maintenance. | ||
| + | Évaluation Différée | ||
| + | |||
| + | C’est un autre des concepts clés de la programmation fonctionnelle. L’évaluation différée, également connue sous le nom de “lazy evaluation” est une approche dans laquelle les expressions ne sont évaluées que lorsque leur valeur est réellement nécessaire. Cela permet d’économiser des ressources en évitant d’évaluer des expressions inutiles. | ||
| + | |||
| + | Pour résumer, ces concepts clés de la programmation fonctionnelle permettent de créer un code plus lisible, prévisible, | ||
| + | Fonctions de Base d’un Langage Fonctionnel | ||
| + | |||
| + | Les fonctions de base d’un langage fonctionnel varient d’un langage à l’autre, mais il existe généralement quelques fonctions couramment utilisées dans la plupart des langages fonctionnels. D’ailleurs, | ||
| + | |||
| + | * map : Applique une fonction à chaque élément d’une liste ou d’une structure de données similaire, renvoyant une nouvelle liste contenant les résultats. | ||
| + | * filter : Filtre les éléments d’une liste en fonction d’une condition spécifiée par une fonction, renvoyant une nouvelle liste ne contenant que les éléments qui satisfont la condition. | ||
| + | * reduce (ou fold) : Combine les éléments d’une liste en appliquant une opération cumulative. Par exemple, une somme, un produit ou une concaténation. | ||
| + | * zip : Combine deux listes (ou plus) en une liste de paires, prenant un élément de chaque liste à chaque fois. | ||
| + | * curry : Transforme une fonction prenant plusieurs arguments en une séquence de fonctions, chaque fonction n’acceptant qu’un seul argument à la fois. | ||
| + | * compose : Permet de composer plusieurs fonctions ensemble pour former une nouvelle fonction. Les sorties d’une fonction deviennent les entrées de la fonction suivante. | ||
| + | |||
| + | Ces fonctions de base permettent de manipuler des données de manière fonctionnelle, | ||
| + | Avantages de la Programmation Fonctionnelle dans les scripts Bash | ||
| + | |||
| + | La programmation fonctionnelle apporte plusieurs avantages à la programmation en Bash qui, le plus souvent, est utilisée en suivant le paradigme procédural : | ||
| + | |||
| + | * Amélioration de la Lisibilité : En se concentrant sur des fonctions concises, autonomes et à usage unique, la programmation fonctionnelle favorise un code plus facile à lire et à comprendre, ce qui le rend plus maintenable dans le temps. | ||
| + | * Modularité et Réutilisabilité : Les fonctions en programmation fonctionnelle sont conçues pour être composables et réutilisables. Cela vous permet de construire des scripts complexes en combinant des fonctions plus petites et autonomes, favorisant ainsi la modularité et la réutilisabilité du code. | ||
| + | * Moins d’Effets Secondaires : La programmation fonctionnelle décourage l’utilisation de l’état mutable et encourage l’immutabilité. Cela réduit la probabilité d’introduire des effets secondaires, | ||
| + | |||
| + | |||
| + | Concepts de Programmation Fonctionnelle appliqués à Bash | ||
| + | |||
| + | |||
| + | ### Fonctions Pures en Bash | ||
| + | |||
| + | Les fonctions pures sont donc la base de la programmation fonctionnelle. Elles prennent des paramètres d’entrée et produisent une sortie sans aucun effet secondaire. En Bash, nous pouvons créer des fonctions pures en veillant à ce qu’elles n’utilisent que des paramètres d’entrée et des variables locales, sans modifier l’état global ni dépendre de dépendances externes. | ||
| + | |||
| + | Exemple : | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Fonction pure pour calculer le carré d'un nombre | ||
| + | carre() { | ||
| + | local num=$1 | ||
| + | echo $((num * num)) | ||
| + | } | ||
| + | |||
| + | # Exemple d' | ||
| + | result=$(carre 2) | ||
| + | |||
| + | echo " | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : 4 | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ### Immutabilité des Données en Bash | ||
| + | |||
| + | L’immutabilité implique que les données ne peuvent pas être modifiées une fois qu’elles sont créées. En Bash, cela peut être réalisé en évitant de modifier directement les variables existantes et en favorisant la création de nouvelles variables lors des transformations. Cela reste donc de la responsabilité du développeur. | ||
| + | |||
| + | Il existe toutefois, dans Bash, l’instruction local pour déclarer une variable locale à une fonction. C’est une pratique courante en programmation fonctionnelle pour éviter les effets de bord et maintenir l’encapsulation des données. L’option -r permet de définir une variable immutable, c’est-à-dire une constante. | ||
| + | |||
| + | Voyons un exemple de son utilisation : | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | my_function() { | ||
| + | local var=" | ||
| + | local -r read_only_var=" | ||
| + | |||
| + | var=" | ||
| + | read_only_var=" | ||
| + | } | ||
| + | |||
| + | my_function | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : bash: read_only_var : variable en lecture seule | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | On voit dans cet exemple que la variable déclarée local n’est pas immutable tandis que celle déclarée avec '' | ||
| + | |||
| + | |||
| + | ### Fonctions d’Ordre Supérieur en Bash | ||
| + | |||
| + | Les fonctions d’ordre supérieur prennent une ou plusieurs fonctions en tant que paramètres d’entrée ou renvoient une fonction en sortie. En Bash, nous pouvons transmettre des fonctions en tant qu’arguments ou les stocker dans des variables, ce qui nous permet de créer des fonctions d’ordre supérieur. | ||
| + | |||
| + | Exemple : | ||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Fonction d' | ||
| + | # à chaque élément d'un tableau | ||
| + | map() { | ||
| + | local func=$1 | ||
| + | local array=(" | ||
| + | local result=() | ||
| + | | ||
| + | for element in " | ||
| + | result+=(" | ||
| + | done | ||
| + | | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Exemple d' | ||
| + | carre() { | ||
| + | local num=$1 | ||
| + | echo $((num * num)) | ||
| + | } | ||
| + | |||
| + | array=(1 2 3 4 5) | ||
| + | result=($(map carre " | ||
| + | echo " | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : 1 4 9 16 25 | ||
| + | ~~~ | ||
| + | |||
| + | ### Récursivité en Bash | ||
| + | |||
| + | La récursivité est une technique puissante en programmation fonctionnelle. Bash, bien qu’il ne soit pas optimisé pour la récursivité, | ||
| + | |||
| + | Exemple : | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Fonction récursive pour calculer le factoriel d'un nombre | ||
| + | factorielle() { | ||
| + | local num=$1 | ||
| + | | ||
| + | if ((num <= 1)); then | ||
| + | echo 1 | ||
| + | else | ||
| + | local sous_factorielle=$(factorielle $((num - 1))) | ||
| + | echo $((num * sous_factorielle)) | ||
| + | fi | ||
| + | } | ||
| + | |||
| + | # Exemple d' | ||
| + | echo $(factorielle 5) | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : 120 | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ### Composition de Fonctions en Bash | ||
| + | |||
| + | La composition est un concept fondamental en programmation fonctionnelle qui consiste à combiner plusieurs fonctions pour créer une nouvelle fonction. L’idée est de prendre le résultat d’une fonction et de l’utiliser comme entrée pour une autre fonction, formant ainsi une chaîne de transformations. Cela permet de diviser un problème complexe en petites étapes plus simples et de les relier entre elles de manière fluide. | ||
| + | |||
| + | Exemple : | ||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Fonction 1 : Convertir le texte en majuscules | ||
| + | to_uppercase() { | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Fonction 2 : Ajouter un préfixe au texte | ||
| + | add_prefix() { | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Fonction 3 : Afficher le texte final | ||
| + | display_text() { | ||
| + | echo "Texte final : $1" | ||
| + | } | ||
| + | |||
| + | # Composition des fonctions | ||
| + | compose_functions() { | ||
| + | local result=" | ||
| + | shift | ||
| + | for func in " | ||
| + | result=" | ||
| + | done | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Utilisation de la composition de fonctions | ||
| + | text=" | ||
| + | |||
| + | result=$(compose_functions " | ||
| + | |||
| + | echo " | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie: Texte final : Prefix EXEMPLE DE TEXTE | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ### Évaluation Différée en Bash | ||
| + | |||
| + | En Bash, bien que ce ne soit pas une caractéristique native du langage, il est possible d’adopter une approche simple pour simuler l’évaluation lazy : l’utilisation de fonctions génératrices. Plutôt que de générer et stocker toutes les valeurs d’une séquence, on pourra générer les valeurs à la demande, lorsqu’elles sont nécessaires, | ||
| + | |||
| + | Exemple d’évaluation différée : | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Fonction lazy : Calcule et retourne la liste des nombres pairs jusqu' | ||
| + | get_even_numbers_lazy() { | ||
| + | local threshold=$1 | ||
| + | local numbers=() | ||
| + | local current=0 | ||
| + | |||
| + | while (( current < threshold )); do | ||
| + | numbers+=($current) | ||
| + | current=$((current + 2)) | ||
| + | done | ||
| + | |||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Utilisation de la fonction lazy | ||
| + | numbers=$(get_even_numbers_lazy 10) | ||
| + | |||
| + | echo "Les nombres pairs jusqu' | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : Les nombres pairs jusqu' | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ## Fonction de Base de la Programmation Fonctionnelle en Bash | ||
| + | |||
| + | ### La Fonction Map | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Définition de la fonction map | ||
| + | map() { | ||
| + | local -n input_list=$1 | ||
| + | local -r transform_fn=$2 | ||
| + | | ||
| + | local mapped_list=() | ||
| + | for element in " | ||
| + | mapped_list+=(" | ||
| + | done | ||
| + | | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Exemple de fonction de transformation | ||
| + | square() { | ||
| + | local input=$1 | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | declare -a my_list=(1 2 3 4 5) | ||
| + | mapped_list=$(map my_list square) | ||
| + | |||
| + | # Affichage du résultat | ||
| + | echo "Liste d' | ||
| + | echo "Liste transformée: | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : Liste d' | ||
| + | # Sortie : Liste transformée: | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ### La Fonction Filter | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Définition de la fonction filter | ||
| + | filter() { | ||
| + | local -n input_list=$1 | ||
| + | local -r predicate=$2 | ||
| + | | ||
| + | local filtered_list=() | ||
| + | for element in " | ||
| + | if " | ||
| + | filtered_list+=(" | ||
| + | fi | ||
| + | done | ||
| + | | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Exemple de fonction filtrante | ||
| + | is_even() { | ||
| + | local input=$1 | ||
| + | ((input % 2 == 0)) | ||
| + | } | ||
| + | |||
| + | declare -a my_list=(1 2 3 4 5) | ||
| + | filtered_list=$(filter my_list is_even) | ||
| + | |||
| + | # Affichage du résultat | ||
| + | echo "Liste d' | ||
| + | echo "Liste filtrée (éléments pairs): ${filtered_list[@]}" | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : Liste d' | ||
| + | # Sortie : Liste filtrée (éléments pairs): 2 4 | ||
| + | ~~~ | ||
| + | |||
| + | ### La Fonction Reduce | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Définition de la fonction reduce | ||
| + | reduce() { | ||
| + | local -n input_list=$1 | ||
| + | local -r accumulate_fn=$2 | ||
| + | local initial_value=$3 | ||
| + | | ||
| + | local accumulator=$initial_value | ||
| + | for element in " | ||
| + | accumulator=" | ||
| + | done | ||
| + | | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Exemple de fonction d' | ||
| + | sum() { | ||
| + | local accumulator=$1 | ||
| + | local element=$2 | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | declare -a my_list=(1 2 3 4 5) | ||
| + | result=$(reduce my_list sum 0) | ||
| + | |||
| + | # Affichage du résultat | ||
| + | echo "Liste d' | ||
| + | echo " | ||
| + | |||
| + | # Sortie : Liste d' | ||
| + | # Sortie : Résultat de la réduction (somme): 15 | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ### La Fonction Zip | ||
| + | |||
| + | ~~~bash | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Définition de la fonction zip | ||
| + | zip() { | ||
| + | local -n input_list1=$1 | ||
| + | local -n input_list2=$2 | ||
| + | | ||
| + | local zipped_list=() | ||
| + | local length=${# | ||
| + | | ||
| + | for ((i=0; i< | ||
| + | zipped_list+=(" | ||
| + | done | ||
| + | | ||
| + | echo " | ||
| + | } | ||
| + | |||
| + | # Exemple d' | ||
| + | declare -a list1=(" | ||
| + | declare -a list2=(" | ||
| + | zipped_list=$(zip list1 list2) | ||
| + | |||
| + | # Affichage du résultat | ||
| + | echo "Liste 1: ${list1[@]}" | ||
| + | echo "Liste 2: ${list2[@]}" | ||
| + | echo "Liste zippée: ${zipped_list[@]}" | ||
| + | ~~~ | ||
| + | |||
| + | ~~~ | ||
| + | # Sortie : Liste 1: a b c | ||
| + | # Sortie : Liste 2: x y z | ||
| + | # Sortie : Liste zippée: a,x b,y c,z | ||
| + | ~~~ | ||
| + | |||
| + | |||
| + | ## Conclusion | ||
| + | |||
| + | Bien que Bash soit principalement un langage impératif, les concepts de programmation fonctionnelle peuvent être appliqués efficacement pour écrire des scripts plus propres et plus modulaires. En exploitant les fonctions pures, les fonctions d’ordre supérieur et la récursivité, | ||
| + | |||
