GNU/Linux >> LINUX-Kenntnisse >  >> Linux

So erstellen Sie Dokumente mit Bash-Skripten

Manchmal müssen Sie mehrzeilige Dokumente mit komplexen verschachtelten Strukturen wie YAML oder HTML aus Bash-Skripten heraus generieren. Sie können dies erreichen, indem Sie einige spezielle Bash-Funktionen verwenden, wie hier Dokumente . Ein „Hier-Dokument“ ist ein Code- oder Textblock, der zu einem Skript oder interaktiven Programm umgeleitet werden kann. Im Wesentlichen wird ein Bash-Skript zu einem Here-Dokument, wenn es zu einem anderen Befehl, Skript oder interaktiven Programm weiterleitet.

In diesem Artikel wird Folgendes erläutert:

  • Verwenden Sie Arrays, Wörterbücher und Zähler
  • Mit verschiedenen Arten von Kommentaren arbeiten
  • Generieren Sie YAML- und HTML-Dokumente
  • E-Mails mit Text und Anhängen senden

[ Jetzt herunterladen:Eine Anleitung für Systemadministratoren zum Bash-Scripting. ]

Ein Skript dokumentieren

Es ist wichtig, Ihre Skripte zu kommentieren, und Sie können einzeilige Kommentare mit einem # erstellen , oder Sie können mehrzeilige Kommentare erstellen, indem Sie die Kombination aus : verwenden und <<ANYTAG .

Zum Beispiel:

# This is a simple comment
: <<COMMENT

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

COMMENT

Diese Hilfefunktion für Ihr Skript ist ein weiteres nützliches Beispiel:

#!/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

Das mehrzeilige Format ist an sich schon ziemlich nützlich, besonders beim Dokumentieren komplexer Skripte. Es gibt jedoch eine nette Wendung bei der Verwendung dieser Dokumente, die Sie vielleicht schon einmal gesehen haben:

$ /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

Folgendes steht in der Datei:

$ /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.

Jetzt werde ich zu etwas anderem übergehen, damit Sie dieses Wissen anwenden können.

[Für weitere Bash-Tipps laden Sie dieses Bash Shell Scripting Cheat Sheet herunter]

Verwenden von Arrays und Wörterbüchern zum Generieren einer Ansible-Inventar-YAML-Datei

Angenommen, Sie haben die folgende CSV-Datei mit einer Liste von Hosts in jeder Zeile, die Server oder Desktops enthält:

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

Sie möchten die Liste in die folgende Ansible-YAML-Inventardatei konvertieren:

---
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        

Zusätzliche Einschränkungen:

  • Jeder Systemtyp (Desktops oder Server) hat eine andere Variable namens description . Durch die Verwendung von Arrays und assoziativen Arrays und Zählern können Sie diese Anforderung erfüllen.
  • Das Skript sollte fehlschlagen, wenn der Benutzer nicht alle richtigen Tags bereitstellt. Eine unvollständige Bestandsaufnahme ist nicht akzeptabel. Für diese Anforderung hilft ein einfacher Zähler.

Dieses Skript erfüllt das Ziel:

#!/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

So sieht die Ausgabe aus:

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

Ein besserer Weg könnte darin bestehen, ein dynamisches Inventar zu erstellen und es vom Ansible-Playbook verwenden zu lassen. Um das Beispiel einfach zu halten, habe ich das hier nicht gemacht.

Versenden von HTML-E-Mails mit YAML-Anhängen

Das letzte Beispiel zeigt Ihnen, wie Sie ein Here-Dokument an Mozilla Thunderbird weiterleiten (Sie können etwas Ähnliches mit /usr/bin/mailx machen ), um eine Nachricht mit einem HTML-Dokument und Anhängen zu erstellen:

#!/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

Dann können Sie das Mailer-Skript aufrufen:

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

Wenn alles wie erwartet läuft, erstellt Thunderbird eine E-Mail wie diese:

Abschluss

Zusammenfassend haben Sie Folgendes gelernt:

  • Verwenden Sie komplexere Datenstrukturen wie Arrays und assoziative Arrays, um Dokumente zu generieren
  • Verwenden Sie Zähler, um Ereignisse zu verfolgen
  • Verwenden Sie diese Dokumente, um YAML-Dokumente, Hilfeanweisungen, HTML usw. zu erstellen.
  • E-Mails mit HTML und YAML versenden

Bash ist in Ordnung, um kleine, unkomplizierte Dokumente zu erstellen. Wenn Sie mit großen oder komplexen Dokumenten arbeiten, ist es möglicherweise besser, eine andere Skriptsprache wie Python oder Perl zu verwenden, um die gleichen Ergebnisse mit weniger Aufwand zu erzielen. Unterschätzen Sie außerdem niemals die Bedeutung eines echten Debuggers, wenn Sie sich mit der Erstellung komplexer Dokumente befassen.


Linux
  1. So erstellen Sie LaTeX-Dokumente mit Emacs

  2. So erstellen Sie eine Datenbank in MySQL mit MySQL Workbench

  3. So erstellen Sie Bash-Skripte mit externen Variablen und eingebetteten Skripten

  4. Wie erstelle ich mit Virsh eine VM von Grund auf neu?

  5. So erstellen Sie eine CPU-Spitze mit einem Bash-Befehl

So erstellen Sie eine Volumengruppe in Linux mit LVM

So erstellen Sie Dokumente in Ubuntu

So verwenden Sie den Echo-Befehl in Bash-Skripten unter Linux

So arbeiten Sie mit Case-Anweisungen in Bash-Skripten

So erstellen Sie einen E-Commerce mit Magento

So erstellen Sie Webspider mit Scrapy