GNU/Linux >> Tutoriels Linux >  >> Linux

Comment créer des documents avec des scripts Bash

Parfois, vous devez générer des documents multilignes avec des structures imbriquées complexes, comme YAML ou HTML, à partir de scripts Bash. Vous pouvez accomplir cela en utilisant certaines fonctionnalités spéciales de Bash, comme documents ici . Un "here doc" est un code ou un bloc de texte qui peut être redirigé vers un script ou un programme interactif. Essentiellement, un script Bash devient un document ici lorsqu'il redirige vers une autre commande, un script ou un programme interactif.

Cet article explique comment :

  • Utiliser des tableaux, des dictionnaires et des compteurs
  • Travailler avec différents types de commentaires
  • Générer des documents YAML et HTML
  • Envoyer des e-mails avec du texte et des pièces jointes

[ Télécharger maintenant :un guide de l'administrateur système sur les scripts Bash. ]

Documenter un script

Il est important de commenter vos scripts, et vous pouvez créer des commentaires sur une seule ligne avec un # , ou vous pouvez avoir des commentaires sur plusieurs lignes en utilisant la combinaison de : et <<ANYTAG .

Par exemple :

# This is a simple comment
: <<COMMENT

This is a multi-line comment
Very useful for some complex comments

COMMENT

Cette fonction d'aide pour votre script est un autre exemple utile :

#!/bin/bash
SCRIPT=$(/usr/bin/basename $0)|| exit 100
export SCRIPT
function help_me {
    /usr/bin/cat<<EOF

$SCRIPT -- A cool script that names and oh wait...
------------------------------------------------------
$SCRIPT --arg1 \$VALUE --arg2 \$VALUE2

EOF

help_me
}

# To use the help function just call help
help_me

Le format multiligne est assez utile en soi, en particulier lors de la documentation de scripts complexes. Cependant, il y a une belle tournure à utiliser ici des documents que vous avez peut-être déjà vus :

$ /usr/bin/cat<<EOF>$HOME/test_doc.txt
Here is a multi-line document that I want to save.
Note how I can use variables inside like HOME=$HOME.

EOF

Voici ce qui est écrit dans le fichier :

$ /usr/bin/cat $HOME/test_doc.txt
Here is a multi-line document that I want to save.
Note how I can use variables inside like HOME=/home/josevnz.

Je vais maintenant passer à autre chose pour que vous puissiez appliquer ces connaissances.

[ Pour plus d'astuces Bash, téléchargez cette feuille de triche pour les scripts shell Bash ]

Utilisation de tableaux et de dictionnaires pour générer un fichier YAML d'inventaire Ansible

Supposons que vous ayez le fichier CSV suivant avec une liste d'hôtes sur chaque ligne contenant des serveurs ou des bureaux :

# List of hosts, tagged by group
macmini2:servers
raspberrypi:servers
dmaf5:desktops
mac-pro-1-1:desktops

Vous souhaitez convertir la liste dans le fichier d'inventaire Ansible YAML suivant :

---
all:
  children:
    servers:
      hosts:
        macmini2:
        raspberrypi:
      vars:
        description: Linux servers for the Nunez family
    desktops:
      hosts:
        dmaf5:
        mac-pro-1-1:
      vars:
        description: Desktops for the Nunez family        

Contraintes supplémentaires :

  • Chaque type de système (bureaux ou serveurs) aura une variable différente appelée description . L'utilisation de tableaux et de tableaux et compteurs associatifs vous permet de répondre à cette exigence.
  • Le script doit échouer si l'utilisateur ne fournit pas toutes les balises correctes. Un inventaire incomplet n'est pas acceptable. Pour cette exigence, un simple compteur vous aidera.

Ce script atteint l'objectif :

#!/bin/bash
:<<DOC
Convert a file in the following format to Ansible YAML:
# List of hosts, tagged by group
macmini2:servers
raspberrypi:servers
dmaf5:desktops
mac-pro-1-1:desktops
DOC
SCRIPT="$(/usr/bin/basename "$0")"|| exit 100
function help {
    /usr/bin/cat<<EOF
Example:
$SCRIPT $HOME/inventory_file.csv servers desktops
EOF
}

# We could use a complicated if-then-else or a case ... esac 
# to handle the tag description logic
# with an Associate Array is very simple
declare -A var_by_tag
var_by_tag["desktops"]="Desktops for the Nunez family"
var_by_tag["servers"]="Linux servers for the Nunez family"

function extract_hosts {
    tag=$1
    host_file=$2
    /usr/bin/grep -P ":$tag$" "$host_file"| /usr/bin/cut -f1 -d':'
    test $? -eq 0 && return 0|| return 1
}
# Consume the host file
hosts_file=$1
shift 1
if [ -z "$hosts_file" ]; then
    echo "ERROR: Missing host file!"
    help
    exit 100
fi

if [ ! -f "$hosts_file" ]; then
    echo "ERROR: Cannot use provided host file: $hosts_file"
    help
    exit 100
fi
# Consume the tags
if [ -z "$*" ]; then
    echo "ERROR: You need to provide one or more tags for the script to work!"
    help
    exit 100
fi
: <<DOC
Generate the YAML
The most annoying part is to make sure the indentation is correct. YAML depends entirely on proper indentation.
The idea is to iterate through the tags and perform the proper actions based on each.
DOC
for tag in "$@"; do # Quick check for tag description handling. Show the user available tags if that happens
    if [ -z "${var_by_tag[$tag]}" ]; then
        echo "ERROR: I don't know how to handle tag=$tag (known tags=${!var_by_tag[*]}). Fix the script!"
        exit 100
    fi
done
/usr/bin/cat<<YAML
---
all:
  children:
YAML
# I do want to split by spaces to initialize my array, this is OK:
# shellcheck disable=SC2207
for tag in "$@"; do
    /usr/bin/cat<<YAML
    $tag:
      hosts:
YAML
    declare -a hosts=($(extract_hosts "$tag" "$hosts_file"))|| exit 100
    host_cnt=0 # Declare your counter
    for host in "${hosts[@]}"; do
        /usr/bin/cat<<YAML
        $host:
YAML
        ((host_cnt+=1)) # This is how you increment a counter
    done
    if [ "$host_cnt" -lt 1 ]; then
        echo "ERROR: Could not find a single host with tag=$tag"
        exit 100
    fi
    /usr/bin/cat<<YAML
      vars:
        description: ${var_by_tag[$tag]}
YAML
done

Voici à quoi ressemble le résultat :

all:
  children:
    servers:
      hosts:
        macmini2:
        raspberrypi:
      vars:
        description: Linux servers for the Nunez family
    desktops:
      hosts:
        dmaf5:
        mac-pro-1-1:
      vars:
        description: Desktops for the Nunez family

Une meilleure façon pourrait être de créer un inventaire dynamique et de laisser le playbook Ansible l'utiliser. Pour garder l'exemple simple, je ne l'ai pas fait ici.

Envoi d'e-mails HTML avec des pièces jointes YAML

Le dernier exemple vous montrera comment diriger un document ici vers Mozilla Thunderbird (vous pouvez faire quelque chose de similaire avec /usr/bin/mailx ) pour créer un message avec un document HTML et des pièces jointes :

#!/bin/bash
:<<HELP
Please take a look a the following document so you understand the Thunderbird command line below:
http://kb.mozillazine.org/Command_line_arguments_-_Thunderbird
HELP
declare EMAIL
EMAIL=$1
test -n "$EMAIL"|| exit 100
declare ATTACHMENT
test -n "$2"|| exit 100
test -f "$2"|| exit 100
ATTACHMENT="$(/usr/bin/realpath "$2")"|| exit 100
declare DATE
declare TIME
declare USER
declare KERNEL_VERSION
DATE=$(/usr/bin/date '+%Y%m%d')|| exit 100
TIME=$(/usr/bin/date '+%H:%M:%s')|| exit 100
USER=$(/usr/bin/id --real --user --name)|| exit 100
KERNEL_VERSION=$(/usr/bin/uname -a)|| exit 100

/usr/bin/cat<<EMAIL| /usr/bin/thunderbird -compose "to='$EMAIL',subject='Example of here documents with Bash',message='/dev/stdin',attachment='$ATTACHMENT'"

<!DOCTYPE html>
<html>
<head>
<style>
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}
</style>
</head>
<body>
<h2>Hello,</p> <b>This is a public announcement from $USER:</h2>
<table>
  <tr>
    <th>Date</th>
    <th>Time</th>
    <th>Kernel version</th>
  </tr>
  <tr>
    <td>$DATE</td>
    <td>$TIME Rovelli</td>
    <td>$KERNEL_VERSION</td>
  </tr>
</table>
</body>
</html>
EMAIL

Ensuite, vous pouvez appeler le script de messagerie :

$ ./html_mail.sh [email protected] hosts.yaml

Si tout se passe comme prévu, Thunderbird créera un e-mail comme celui-ci :

Conclusion

Pour récapituler, vous avez appris à :

  • Utiliser des structures de données plus sophistiquées telles que des tableaux et des tableaux associatifs pour générer des documents
  • Utilisez des compteurs pour suivre les événements
  • Utilisez ici des documents pour créer des documents YAML, des instructions d'aide, HTML, etc.
  • Envoyer des e-mails avec HTML et YAML

Bash convient pour générer de petits documents simples. Si vous traitez des documents volumineux ou complexes, il peut être préférable d'utiliser un autre langage de script comme Python ou Perl pour obtenir les mêmes résultats avec moins d'effort. De plus, ne sous-estimez jamais l'importance d'un véritable débogueur lorsqu'il s'agit de créer des documents complexes.


Linux
  1. Comment créer des documents LaTeX avec Emacs

  2. Comment créer une base de données dans MySQL avec MySQL Workbench

  3. Comment créer des scripts Bash à l'aide de variables externes et de scripts intégrés

  4. Comment créer une VM à partir de zéro avec Virsh ?

  5. Comment créer un pic CPU avec une commande bash

Comment créer un groupe de volumes sous Linux avec LVM

Comment créer des documents dans Ubuntu

Comment utiliser la commande echo dans les scripts Bash sous Linux

Comment travailler avec l'instruction Case dans les scripts Bash

Comment créer un e-commerce avec Magento

Comment créer des araignées Web avec Scrapy