Terkadang Anda perlu membuat dokumen multi-baris dengan struktur bersarang yang kompleks, seperti YAML atau HTML, dari dalam skrip Bash. Anda dapat melakukannya dengan menggunakan beberapa fitur Bash khusus, seperti dokumen di sini . "di sini doc" adalah kode atau blok teks yang dapat diarahkan ke skrip atau program interaktif. Pada dasarnya, skrip Bash menjadi dokumen di sini saat dialihkan ke perintah, skrip, atau program interaktif lain.
Artikel ini menjelaskan cara:
- Gunakan larik, kamus, dan penghitung
- Bekerja dengan berbagai jenis komentar
- Buat dokumen YAML dan HTML
- Kirim email dengan teks dan lampiran
[ Unduh sekarang:Panduan sysadmin untuk skrip Bash. ]
Mendokumentasikan skrip
Penting untuk mengomentari skrip Anda, dan Anda dapat membuat komentar satu baris dengan #
, atau Anda dapat memiliki komentar multi-baris dengan menggunakan kombinasi :
dan <<ANYTAG
.
Misalnya:
# This is a simple comment
: <<COMMENT
This is a multi-line comment
Very useful for some complex comments
COMMENT
Fungsi bantuan untuk skrip Anda ini adalah contoh lain yang berguna:
#!/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
Format multi-baris cukup berguna dengan sendirinya, terutama saat mendokumentasikan skrip yang kompleks. Namun, ada perubahan bagus untuk menggunakan dokumen di sini yang mungkin pernah Anda lihat sebelumnya:
$ /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
Berikut yang tertulis dalam file tersebut:
$ /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.
Sekarang saya akan beralih ke hal lain sehingga Anda dapat menerapkan pengetahuan ini.
[ Untuk kiat Bash lainnya, unduh Lembar Cheat Scripting Bash Shell ini ]
Menggunakan array dan kamus untuk menghasilkan file YAML inventaris yang memungkinkan
Misalnya Anda memiliki file CSV berikut dengan daftar host di setiap baris yang berisi server atau desktop:
# List of hosts, tagged by group
macmini2:servers
raspberrypi:servers
dmaf5:desktops
mac-pro-1-1:desktops
Anda ingin mengonversi daftar ke file inventaris YAML yang Dimungkinkan berikut:
---
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
Batasan ekstra:
- Setiap jenis sistem (desktop atau server) akan memiliki variabel berbeda yang disebut
description
. Menggunakan larik dan larik asosiatif serta penghitung memungkinkan Anda memenuhi persyaratan ini. - Skrip akan gagal jika pengguna tidak memberikan semua tag yang benar. Inventaris yang tidak lengkap tidak dapat diterima. Untuk persyaratan ini, penghitung sederhana akan membantu.
Skrip ini mencapai tujuan:
#!/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
Berikut tampilan outputnya:
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
Cara yang lebih baik adalah dengan membuat inventaris dinamis dan membiarkan buku pedoman Ansible menggunakannya. Untuk menjaga agar contoh tetap sederhana, saya tidak melakukannya di sini.
Mengirim email HTML dengan lampiran YAML
Contoh terakhir akan menunjukkan kepada Anda cara menyalurkan dokumen di sini ke Mozilla Thunderbird (Anda dapat melakukan sesuatu yang mirip dengan /usr/bin/mailx
) untuk membuat pesan dengan dokumen HTML dan lampiran:
#!/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
Kemudian Anda dapat memanggil skrip mailer:
$ ./html_mail.sh [email protected] hosts.yaml
Jika semuanya berjalan seperti yang diharapkan, Thunderbird akan membuat email seperti ini:
Menutup
Untuk rekap, Anda telah mempelajari cara:
- Gunakan struktur data yang lebih canggih seperti array dan array asosiatif untuk membuat dokumen
- Gunakan penghitung untuk melacak acara
- Gunakan dokumen di sini untuk membuat dokumen YAML, petunjuk bantuan, HTML, dll.
- Kirim email dengan HTML dan YAML
Bash dapat digunakan untuk membuat dokumen kecil yang tidak rumit. Jika Anda berurusan dengan dokumen besar atau kompleks, Anda mungkin lebih baik menggunakan bahasa skrip lain seperti Python atau Perl untuk mendapatkan hasil yang sama dengan sedikit usaha. Selain itu, jangan pernah meremehkan pentingnya debugger nyata saat menangani pembuatan dokumen yang rumit.