Les bases de l'écriture de scripts Bash

Les scripts shell sont largement utilisés dans le monde UNIX. Ils sont excellents pour accélérer les tâches répétitives et simplifier la logique d'exécution complexe. Elles peuvent être aussi simples qu’un ensemble de commandes ou orchestrer des tâches complexes. Dans ce tutoriel, nous en apprendrons plus sur le langage de script Bash en écrivant un exemple de script pas à pas..


Le problème de Fizz-Buzz

L'un des meilleurs moyens d'apprendre une nouvelle langue est de donner l'exemple. Commençons par un.

Le problème de Fizz-Buzz est très simple. Il est devenu célèbre après qu'un programmeur, nommé Imran, l'ait utilisé comme test d'interview. Il s'avère que 90 à 99,5% des candidats à un poste de programmation sont tout simplement incapables d'écrire le programme le plus simple. Imran a pris ce simple jeu Fizz-Buzz et a demandé aux candidats de le résoudre. Beaucoup ont suivi l'exemple d'Imran et, aujourd'hui, c'est l'une des questions les plus fréquemment posées pour un travail de programmation. Si vous embauchez et avez besoin d’un moyen de filtrer 90% des candidats, c’est un gros problème.

Voici les règles:

  • Prenez et imprimez les nombres entre 1 et 100.
  • Lorsqu'un nombre est divisible par 3, écrivez "Fizz" au lieu du nombre.
  • Quand il est divisible par 5, écrivez "Buzz" à la place.
  • Quand il est divisible par 3 et 5, imprimez "FizzBuzz".

C'est tout ce qu'on peut en dire. Je suis sûr que la plupart d'entre vous peuvent déjà visualiser les deux ou trois si déclarations pour résoudre ce problème. Travaillons à travers cela en utilisant le langage de script Bash.


Case

Un shebang fait référence à la combinaison des caractères dièse et d'exclamation: #!. Le chargeur de programme cherchera un shebang sur la première ligne du script et utilisera l'interpréteur spécifié dans celle-ci. Un shebang comprend la syntaxe suivante: #!interpréteur [paramètres]. L'interprète est le programme utilisé pour interpréter notre langue. Pour le script bash, ce serait / bin / bash. Par exemple, si vous voulez créer un script en PHP et l’exécuter dans la console, vous voudrez probablement utiliser / usr / bin / php (ou le chemin de l'exécutable PHP sur votre machine) en tant qu'interprète.

#! / usr / bin / php  

Oui, cela fonctionnera réellement! N'est-ce pas simple? Assurez-vous simplement que votre fichier est d'abord exécutable. Une fois que vous avez terminé, ce script affichera vos informations PHP comme vous le souhaitiez..

Pointe: Pour vous assurer que votre script fonctionnera sur autant de systèmes que possible, vous pouvez utiliser / bin / env dans le shebang. En tant que tel, au lieu de / bin / bash, vous pourriez utiliser / bin / env bash, qui fonctionnera sur les systèmes où l'exécutable bash n'est pas dans /poubelle.


Sortie de texte

La sortie d'un script sera égale à, comme vous pouvez vous y attendre, à tout ce qui sort de votre commande. Cependant, si nous voulons explicitement écrire quelque chose à l’écran, nous pouvons utiliser écho.

#! / bin / bash echo "Hello World"

L'exécution de ce script imprimera "Hello World" dans la console.

csaba @ csaba ~ $ ./helloWorld.sh Bonjour le monde csaba @ csaba ~ $

Introduction aux variables

Comme avec n’importe quel langage de programmation, lors de l’écriture de scripts shell, vous pouvez utiliser des variables..

#! / bin / bash message = "Hello World" echo $ message

Ce code produit exactement le même message "Hello World". Comme vous pouvez le constater, pour attribuer une valeur à une variable, écrivez simplement son nom - excluez le signe dollar devant celle-ci. Aussi, soyez prudent avec les espaces; il ne peut y avoir aucun espace entre le nom de la variable et le signe égal. Alors message = "Bonjour" au lieu de message = 'Bonjour'

Lorsque vous souhaitez utiliser une variable, vous pouvez en prendre la valeur comme nous l’avons fait dans le cas précédent. écho commander. Préposer un $ au nom de la variable retournera sa valeur.

Pointe: Les points-virgules ne sont pas requis dans les scripts bash. Vous pouvez les utiliser dans la plupart des cas, mais soyez prudent: leur signification peut être différente de celle à laquelle vous vous attendez..


Imprimer les nombres entre 1 et 100

Poursuivant notre projet de démonstration, nous devons parcourir tous les nombres compris entre 1 et 100. Pour cela, nous devons utiliser un pour boucle.

#! / bin / bash pour le nombre dans 1… 100; echo $ number done

Il y a plusieurs nouvelles choses à noter dans cet exemple - qui, en passant, imprime tous les nombres de 1 à 100, un numéro à la fois..

  • le pour La syntaxe dans Bash est la suivante: pour VARIABLE en GAMME; faire le commandement fait.
  • Les accolades vont transformer 1100 dans une plage dans notre exemple. Ils sont également utilisés dans d'autres contextes, que nous examinerons bientôt.
  • faire et pour sont en fait deux commandes distinctes. Si vous souhaitez placer deux commandes sur une seule ligne, vous devez les séparer d'une manière ou d'une autre. Une solution consiste à utiliser le point-virgule. Sinon, vous pouvez écrire le code sans point-virgule en déplaçant faire à la ligne suivante.
#! / bin / bash pour le nombre dans 1… 100 do echo $ number done

La première décision

Maintenant que nous savons imprimer tous les nombres compris entre 1 et 100, il est temps de prendre notre première décision..

#! / bin / bash pour le nombre dans 1… 100; faire si [$ ((nombre% 3)) -eq 0]; then echo "Fizz" sinon echo $ number fi terminé

Cet exemple produira "Fizz" pour les nombres divisibles par 3. Encore une fois, nous devons traiter un peu de nouvelle syntaxe. Prenons les un par un.

  • si… alors… sinon… fi - c'est la syntaxe classique pour un si déclaration dans Bash. Bien sûr, le autre une partie est optionnelle - mais nécessaire pour notre logique dans ce cas.
  • si COMMAND-RETURN-VALUE; puis… - si s'exécutera si la valeur de retour de la commande est zéro. Oui, la logique dans Bash est basée sur zéro, ce qui signifie que les commandes qui s'exécutent avec succès se terminent par un code de 0. En cas d'incident, un entier positif est renvoyé. Pour simplifier les choses: on considère autre chose que 0 faux.
  • Les expressions mathématiques dans Bash sont spécifiées par des doubles parenthèses. $ ((nombre% 3)) retournera la valeur restante de la division de la variable, nombre, par 3. S'il vous plaît noter que nous n'avons pas utilisé $ à l'intérieur de la parenthèse - seulement devant eux.

Vous vous demandez peut-être où se trouve la commande dans notre exemple. N'y a-t-il pas juste un support avec une expression étrange? Eh bien, il s'avère que [ est en fait une commande exécutable. Pour jouer avec cela, essayez les commandes suivantes dans votre console.

csaba @ csaba ~ $ qui [/ usr / bin / [csaba @ csaba ~ $ [0 -eq 1] csaba @ csaba ~ $ echo $? 1 csaba @ csaba ~ $ [0 -eq 0] csaba @ csaba ~ $ echo $? 0

Pointe: La valeur de sortie d'une commande est toujours renvoyée dans la variable, ? (point d'interrogation). Il est écrasé après l'exécution de chaque nouvelle commande.


Vérification de buzz

Nous allons bien jusqu'à présent. Nous avons "Fizz"; faisons maintenant la partie "Buzz".

#! / bin / bash pour le nombre dans 1… 100; faire si [$ ((nombre% 3)) -eq 0]; puis echo "Fizz" elif [$ ((number% 5)) -eq 0]; then echo "Buzz" sinon echo $ number fi terminé

Ci-dessus, nous avons introduit une autre condition de divisibilité par 5: la elif déclaration. Ceci, bien sûr, se traduit par sinon si, et sera exécuté si la commande qui le suit retourne vrai (ou 0). Comme vous pouvez le constater, les instructions conditionnelles de [] sont généralement évalués à l’aide de paramètres tels que -eq, qui signifie "égaux".

Pour la syntaxe, arg1 OP arg2, OP fait partie de -eq, -ne, -lt, -le, -gt, ou -ge. Ces opérateurs binaires arithmétiques retournent vrai si arg1 est égal, égal ou inférieur à, inférieur ou égal, supérieur ou supérieur ou égal à arg2, respectivement.arg1 et arg2 peut être des entiers positifs ou négatifs. - Manuel Bash

Lorsque vous essayez de comparer des chaînes, vous pouvez utiliser le bien connu == signe, ou même un seul signe égal fera. != résultats vrai quand les cordes sont différentes.


Mais le code n'est pas tout à fait correct

Jusqu'à présent, le code est exécuté, mais la logique n'est pas correcte. Lorsque le nombre est divisible par 3 et 5, notre logique ne fera écho que "Fizz". Modifions notre code pour satisfaire à la dernière exigence de FizzBuzz.

#! / bin / bash pour le nombre dans 1… 100; faire si [$ ((nombre% 3)) -eq 0]; alors output = "Fizz" fi si [$ ((nombre% 5)) -eq 0]; then output = "$ output Buzz" fi if [-z $ output]; then echo $ number else echo $ output; fi fait

Encore une fois, nous avons dû apporter une poignée de changements. Le plus notable est l'introduction d'une variable, puis la concaténation de "Buzz", si nécessaire. Les chaînes en bash sont généralement définies entre guillemets doubles ("). Les guillemets simples sont également utilisables, mais pour faciliter la concaténation, les doubles sont le meilleur choix. Dans ces guillemets, vous pouvez référencer des variables: un texte $ variable un autre texte" remplacera $ variable avec son contenu. Lorsque vous souhaitez concaténer des variables avec des chaînes sans espaces, vous pouvez préférer mettre le nom de la variable entre accolades. Dans la plupart des cas, comme PHP, vous n'êtes pas obligé de le faire, mais cela aide beaucoup pour la lisibilité du code..

Pointe: Vous ne pouvez pas comparer les chaînes vides. Cela retournerait un paramètre manquant.

Parce que les arguments à l'intérieur [] sont traités comme des paramètres, pour "[", ils doivent être différents d'une chaîne vide. Donc, cette expression, même si elle est logique, générera une erreur: [$ output! = ""]. C'est pourquoi nous avons utilisé [-z $ sortie], qui retourne vrai si la chaîne a une longueur de zéro.


Méthode d'extraction pour expression logique

L’un des moyens d’améliorer notre exemple consiste à extraire en fonctions l’expression mathématique du si déclarations, comme si:

#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2)) pour le nombre entre 1… 100; faire si isDivisibleBy $ number 3; then output = "Fizz" fi si isDivisibleBy $ number 5; then output = "$ output Buzz" fi if [-z $ output]; then echo $ number else echo $ output; fi fait

Nous avons pris les expressions comparant le reste à zéro et les avons déplacées dans une fonction. Encore plus, nous avons éliminé la comparaison avec zéro, car zéro signifie vrai pour nous. Il suffit de renvoyer la valeur de l'expression mathématique - très simple!

Pointe: La définition d'une fonction doit précéder son appel.

En Bash, vous pouvez définir une méthode comme function nom_fonction commandes; . Il existe éventuellement une deuxième syntaxe pour déclarer des fonctions: nom_fonction () commandes; . Donc, nous pouvons laisser tomber la chaîne, une fonction et ajouter "()" d'après son nom. Personnellement, je préfère cette option, comme dans l'exemple ci-dessus. C'est plus explicite et ressemble aux langages de programmation traditionnels.

Vous n'avez pas besoin de spécifier les paramètres d'une fonction dans Bash. Pour envoyer des paramètres à une fonction, il suffit de les énumérer après l’appel de la fonction, séparés par des espaces. Ne placez pas de virgules ni de parenthèses dans l'appel de fonction - cela ne fonctionnera pas.

Les paramètres reçus sont automatiquement affectés aux variables par numéro. Le premier paramètre va à 1 $, la seconde à 2 $, etc. La variable spéciale, 0 $ fait référence au nom de fichier du script actuel.

Jouons avec les paramètres

#! / bin / bash function exampleFunc echo $ 1 echo $ 0 IFS = "X" echo "$ @" echo "$ *" exempleFunc "un" "deux" "trois"

Ce code produira la sortie suivante:

csaba @ csaba ~ $ ./parametersExamples.sh one ./parametersExamples.sh un deux trois oneXtwoXthre

Analysons la source, ligne par ligne.

  • La dernière ligne est l'appel de fonction. Nous l'appelons avec trois paramètres de chaîne.
  • La première ligne après le shebang est la définition de la fonction.
  • La première ligne de la fonction génère le premier paramètre: "un". Jusqu'ici si simple.
  • La deuxième ligne affiche le nom du fichier du script actuel. Encore une fois, très simple.
  • La troisième ligne remplace le séparateur de caractères par défaut par la lettre "X". Par défaut, c'est "" (un espace). Voilà comment Bash sait comment les paramètres sont séparés.
  • La quatrième ligne génère une variable spéciale, $ @. Il représente tous les paramètres sous la forme d'un mot unique, exactement comme spécifié dans l'appel de fonction..
  • La dernière ligne fournit une autre variable spéciale, $ *. Il représente tous les paramètres, pris un par un et concaténés avec la première lettre de la variable IFS. Voilà pourquoi le résultat est oneXtwoXthre.

Renvoi de chaînes à partir de fonctions

Comme je l'ai indiqué précédemment, les fonctions de Bash ne peuvent renvoyer que des entiers. En tant que tel, l'écriture retourne "une chaîne" serait un code invalide. Pourtant, dans de nombreuses situations, il vous faut plus qu'un zéro ou un. Nous pouvons refactoriser notre exemple FizzBuzz afin que, dans le pour déclaration, nous allons juste faire un appel de fonction.

#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz if isDivisibleBy $ 1 3; then output = "Fizz" fi si isDivisibleBy $ 1 5; then output = "$ output Buzz" fi if [-z $ output]; then echo $ 1 else echo $ output; fi pour le nombre entre 1… 100; faire fizzOrBuzz $ nombre fait

Eh bien, c'est la première étape. Nous venons d'extraire tout le code dans une fonction, appelée fizzOrBuzz, puis remplacé numéro $ avec 1 $. Cependant, toutes les sorties ont lieu dans le fizzOrBuzz une fonction. Nous voulons sortir de la pour boucle avec un écho déclaration, de sorte que nous pouvons ajouter chaque ligne avant une autre chaîne. Nous devons capturer le fizzOrBuzz la sortie de la fonction.

# […] Pour le nombre entre 1… 100; fait echo "-'fizzOrBuzz $ number '" fizzBuzzer = $ (fizzOrBuzz $ number) echo "- $ fizzBuzzer" done

Nous avons mis à jour notre pour boucle juste un peu (pas d'autres changements). Nous avons maintenant répété deux fois le tout de deux manières différentes pour illustrer les différences entre les deux solutions au même problème..

La première solution pour capturer la sortie d'une fonction ou d'une autre commande consiste à utiliser des backticks. Dans 99% des cas, cela fonctionnera très bien. Vous pouvez simplement référencer une variable à l'intérieur des backticks par leurs noms, comme nous l'avons fait avec numéro $. Les premières lignes de la sortie devraient maintenant ressembler à ceci:

csaba @ csaba ~ / Personnel / Programmation / NetTuts / Notions de base de BASH Scripting / Sources $ ./fizzBuzz.sh -1 -1 -2 -2 -Fizz -Fizz -4 -4 -Buzz -Buzz -Fizz -Fizz -7 -7

Comme vous pouvez le constater, tout est dupliqué. Même sortie.

Pour la deuxième solution, nous avons choisi d’attribuer d’abord la valeur de retour à une variable. Dans cette mission, nous avons utilisé $ (), qui, dans ce cas, forque le script, exécute le code et renvoie sa sortie.


;, && et ||

Vous souvenez-vous que nous avons utilisé le point-virgule ici et là? Ils peuvent être utilisés pour exécuter plusieurs commandes écrites sur la même ligne. Si vous les séparez par des points-virgules, ils seront simplement exécutés.

Un cas plus sophistiqué consiste à utiliser && entre deux commandes. Oui, c'est un ET logique; cela signifie que la seconde commande ne sera exécutée que si la première retourne vrai (il sort avec 0). C'est utile; on peut simplifier le si déclarations dans ces raccourcis:

#! / bin / bash function isDivisibleBy return $ (($ 1% $ 2)) function fizzOrBuzz isDivisibleBy $ 1 3 && output = "Fizz" estDivisibleBy $ 1 5 && output = "$ output Buzz" si [-z $ sortie ]; then echo $ 1 else echo $ output; fi pour le nombre entre 1… 100; echo "-'fizzOrBuzz $ number '" terminé

Comme notre fonction, isDivisibleBy renvoie une valeur de retour appropriée, nous pouvons alors utiliser && pour définir la variable que nous voulons. Après quoi && sera exécuté que si la condition est vrai. De la même manière, nous pouvons utiliser || (caractère double-pipe) en tant que OU logique. Voici un exemple rapide ci-dessous.

csaba @ csaba ~ $ echo "bubu" || echo "bibi" bubu csaba @ csaba ~ $ echo false || echo "bibi" faux csaba @ csaba ~ $

Dernières pensées

Donc ça le fait pour ce tutoriel! J'espère que vous avez découvert une poignée de nouvelles astuces et techniques pour écrire vos propres scripts Bash. Merci de votre lecture et restez à l’écoute pour des articles plus avancés sur ce sujet.