Filtern in Bash

Manchmal will man aus einer Variable oder einem Text alle Zahlen herausziehen oder verstecken. Das geht natürlich mit sed ganz gut, aber noch einfacher in der Bash selbst.

% VAR=1a2b3c4d
% echo "${VAR//[!0-9]/}"
1234
% echo "${VAR//[0-9]/}"
abcd

Man kann auch nur Buchstaben filtern, damit man Sonderzeichen mit herausfiltert. Oder oder…

% VAR="1a,2b.3c;4d"
% echo "${VAR//[!0-9]/}"
1234
% echo "${VAR//[!a-z]/}"
abcd
% echo "${VAR//[!a-z 0-9]/}"
1a2b3c4d
% echo "${VAR//[a-z 0-9]/}"
,.;
Advertisements
Filtern in Bash

HTML emails mit mail.mailutils

Das Programm mail.mailutils (meist einfach mail) ist auf vielen Linux-Distributionen installiert. Man kann damit über die Shell Emails verschicken, was sehr praktisch ist für scripte und cron-jobs, die den Admin per Mail informieren sollen.

Manchmal will man auch mal ein wenig mit HTML spielen und sei es auch nur, um um den Text ein <pre> zu setzen, damit er mit einer Monospace-Schrift angezeigt wird und ASCII-Art und Tabellen ordentlich dargestellt werden.

So schickt man HTML:

# generiere random boundary
BOUNDARY=$(date | md5sum | head -c8)
echo "
--_$BOUNDARY_
Content-Type: text/html; charset=\"us-ascii\"
Content-Transfer-Encoding: quoted-printable

<html><pre>
Meine Tabelle

+-------+----------+
| id    | analysis |
+-------+----------+
| 36190 |      219 |
| 36192 |      219 |
| 36273 |      219 |
| 36275 |       -1 |
| 36276 |       -1 |
| 36289 |      219 |
| 36293 |      122 |
| 36371 |      219 |
| 36388 |      219 |
| 36393 |      219 |
| 36394 |       -1 |
| 36395 |       -1 |
| 36708 |      122 |
+-------+----------+
</pre></html>
--_$BOUNDARY_--

" | mail.mailutils -s "Mein Subject" \
-a Content-Type:"multipart/alternative; boundary="\"_$BOUNDARY_\"" \
-a From:mein@absender.tld mein@empfaenger.tld

Diese Tabelle sieht jetzt sauber aus, wenn sie den Empfänger erreicht. Die Leerzeilen vor und nach dem Boundary und/oder Headern sind wichtig!

Wenn ich ein Bild in das HTML einbetten will, wird es komplizierter. Das mail-Tool kann zwar mit -A Anhänge verschicken, aber die kann ich dann nicht im HTML nutzen, da ich die dazugehörige ID nicht kenne.
Also muss ich das händisch machen, damit ich alle Parameter kontrollieren kann. Da Email ein 7-Bit Medium ist, muss ich aus dem Binär-Bild ASCII machen und dann noch dem Mailprogramm erklären, wie es das ASCII wieder in eine Binär-Bilddatei zurückverwandelt. Ich benutze hier base64 dafür, da das standardmässig installiert ist und so ziemlich jedes Mailprogramm das versteht. Ausserdem muss ich dem Bild einen Namen geben, denn der Dateiname geht verloren beim encoden in base64, und dazu eine ID, mit der ich darauf verweisen kann im HTML-Code der Mail. So gehts:

# generiere random boundary und Image ID
BOUNDARY=$(date | md5sum | head -c8)
IMAGEID=$(date | md5sum | head -c10 | rev)
# meine Bilddatei
IMAGEFILE=graph.png
( echo "
--_$BOUNDARY_
Content-Type: text/html; charset=\"us-ascii\"
Content-Transfer-Encoding: quoted-printable

<html>
Mein Graph als Bild:<br>
<img contenttype=3D\"image/png\" src=3D\"cid:$IMAGEID\"><br>
Sieht gut aus!

</pre></html>

--_$BOUNDARY_
Content-Type: image/png;name=\"$IMAGEFILE\"
Content-Disposition: attachment;filename=\"$IMAGEFILE\"
Content-ID: <$IMAGEID>
Content-Transfer-Encoding: base64 
"
base64 $IMAGEFILE 
echo "
--_$BOUNDARY_--" ) |  mail.mailutils -s "Mein Subject" \
-a Content-Type:"multipart/related; boundary="\"_$BOUNDARY_\""; type="\"multipart/alternative\""" \
-a MIME-Version:"1.0" \
-a From:mein@absender.tld mein@empfaenger.tld

Es gibt ausser mail.mailutils noch viele andere Commandline-Mailer wie etwa mutt oder mailx. Mit Hilfe der Beispiele oben kann man auch diese Mailer dazu bringen, HTML zu verschicken. Einfach mal gucken, welche Tools auf dem System installiert sind. Auch OS X kann das.

HTML emails mit mail.mailutils

Alles so schön bunt hier!

Um in der Shell bunten Text auszugeben, kann man echo oder printf nutzen. Bei ersterem muss man die erweiterten Fähigkeiten mit -e aufrufen.

Hier ein Beispiel für farbigen Text mit fetten Buchstaben und normalen Buchstaben ohne Farbe:

echo -e "\e[1;31mRot\e[0m Normal \e[1;32mGruen \e[0m"

Das Ergebnis ist:

Rot Normal Gruen

Hier ein Beispiel für gelben Text blau hinterlegt und hunterstrichen:

echo -e "\e[4;44;33mGelb blau hinterlegt und unterstrichen\e[0m"

Das Ergebnis ist:

Gelb blau hinterlegt und unterstrichen

Zur Erklärung:

Mit \e[ leitet man die Farb und Formatierungscodes ein. Danach kommen in beliebiger reihenfolge Codes für Zeichen- und Hintergrundfarbe und Formatierung durch Semikolon unterteilt. Danach ein m zum Abschluss. Am Ende des Textes folgt noch ein \e[0m um alle Formatierungen wieder aufzuheben, da sonst aller nachfolgender Text, also auch die übliche Console, eingefärbt bleibt. Hier die Tabellen für die Farben und Formatierungen:

 

Farbe Zeichen Hintergrund
Schwarz 30 40
Rot 31 41
Grün 32 42
Gelb 33 43
Blau 34 44
Magenta 35 45
Cyan 36 46
Weiss 37 47

 

Code Formatierung
0 Normal, Aufheben von allem
1 Fett
2 Gedimmt
3 Kursiv
4 Unterstrichen
5 Blinkend (funktioniert nicht überall)
7 Farbumdrehung (einfach mal ausprobieren!)
8 Unsichtbar
9 Durchgestrichen
Alles so schön bunt hier!

<html>-Tags löschen

Um aus einer Datei alle html-Tags zu löschen, bietet sich sed an. Ich dachte erst, das geht einfach so:

's/<.*>//g'

Aber damit löscht mann alles zwischen dem ersten < und dem letzten >. So geht es:

sed -e 's/<[^>]*>//g'

Warum? Dinge in eckigen Klammern sind Zeichenklassen, etwa steht [0-9] für alle Zahlen. Steht ein ^ davor, dann dreht es das um, also alles, was nicht in der Klammer steht. Beispiele:

$ echo t12e34x5678t | sed 's/[0-9]//g'
text
$ echo t12e34x5678t | sed 's/[^0-9]//g'
12345678

Im obigen Befehl werden alle Zeichen vom < und null oder beliebig viele, die nicht > sind bis zum > ersetzt.

<html>-Tags löschen

Zähl hoch, bash!

Wenn man in der bash ein Script schreibt, das aus irgend welchen Gründen hoch zählen muss, dann kann man eine Variable definieren, zu der man in einer Schleife eine eins addiert. Dieses Script zählt von 1 bis 10:

N=1
while [ $N -le 10 ]; do
   echo Zeile $N
   ((N++))
done

Noch einfacher kann man dieses Script mit Hilfe von „seq“ realisieren:

for N in $(seq 1 10); do
   echo Zeile $N
done

Ausgabe in beiden Fällen:

Zeile 1
Zeile 2
Zeile 3
Zeile 4
Zeile 5
Zeile 6
Zeile 7
Zeile 8
Zeile 9
Zeile 10

Die bash versteht aber (im Gegensatz zur sh) auch den Befehl „let“, mit dem man auch andere Operationen mit ganzzahligem Ergebnis machen kann als nur +1. Dabei rundet „let“ grundsätzlich ab:

N=110
while [ $N -ge 1 ]; do
   echo Ergebnis $N
   let N=$N/3
done

Ausgabe:

Ergebnis 110
Ergebnis 36
Ergebnis 12
Ergebnis 4
Ergebnis 1

Braucht man noch komplexere Ergebnisse mit Bruchzahlen oder will von Dec nach Bin oder Hex umrechnen, dann hilft das Programm bc, das auf den meisten U*ix Distries vorinstalliert ist. Dieses Script zählt alle geraden Zahlen von 2 – 20 und gibt das Ergebnis als Hex aus

N=2
while [ $N -le 20 ]; do
   echo -n "$N in Hex ist "
   echo "obase=16; $N" | bc
   N=$(echo "$N+2" | bc)
done

Ausgabe:

2 in Hex ist 2
4 in Hex ist 4
6 in Hex ist 6
8 in Hex ist 8
10 in Hex ist A
12 in Hex ist C
14 in Hex ist E
16 in Hex ist 10
18 in Hex ist 12
20 in Hex ist 14

Aber Achtung! Der test-Befehl (hier durch die [] aufgerufen) kann nur ganzzahlige Werte vergleichen. Die Schleife wird also nicht funktionieren, wenn man Zahlen mit Kommastellen als Ergebnis hat. Der Rechner bc rundet in der Standardeinstellung das Endergebnis auf ganzzahlige Werte ab, genau wie let, aber etwa mit „scale=2“ kann man auch zwei Kommastellen ausgeben (oder mehr, bei höherem scale):

 echo "scale=2; 8/3" | bc

Ausgabe:

2.66
Zähl hoch, bash!