Kategorien
Linux

Die Bash und IFS – Zeilenschaltungen als Feldtrenner

Heute habe ich mal wieder etwas gelernt, wie eigentlich jeden Tag! 🙂

Mit der Variable IFS kann man in der Bash den Feldtrenner angeben, da ich als Feldtrenner die Zeilenschaltung erkennen wollte habe ich ihn auf „\n“ gesetzt.

Das klappt so lange im String kein „n“ enthalten ist!


Sobald aber im String ein „n“ enthalten ist wird dieses auch als Trenner erkannt und entsprechend passt das Ergebnis dann nicht mehr:

Die Lösung des Problems ist folgende:

IFS=$’\n‘

Damit klappt es dann wie gewünscht:

Kategorien
Linux

Bounced Mails am IMAP Server finden und erneut versenden

Was tun wenn durch einen Fehler jede Menge Mails vom Mailserver gebounced wurden und man es nicht allen Leuten zumuten möchte dass sie die Mails erneut versenden müssen?

Alle an diesem Tag gesendeten Mails finden und via Script erneut in die Mail-Queue einordnen – was so einfach klingt ist im Grunde auch so einfach! (fast) 😉

Angenommen die gesendeten Mails liegen alle im Verzeichnis /srv/imap/{benutzer}/Maildir/.Sent/cur/ – dann könnte man anhand des Dateinamens schon mal ein wenig eingrenzen, alle Mails vom 19. und 20. Juli beginnen mit 1532… (Unix Timestamp).

Wir suchen also alle Mails die mit 1532 beginnen und prüfen dann mit „ls -al“ und grep ob sie an besagtem Tag versendet wurden – es interessieren uns nur die vom 20. Juli.

Alle Mails die gefunden werden injizieren wir dann unserem Postfix mit dem „sendmail“ Kommando.

#!/bin/bash

cd /srv/imap/

IFS=“

for I in $(ls);do

if [ -d „$I/Maildir/.Sent“ ]; then
for F in $(ls -al $I/Maildir/.Sent/cur/1532* 2>&1 |grep -v „No such file or directory“);do
TOSEND=$(echo $F|grep „Jul 20″|awk ‚{print $9}‘)
if [ $TOSEND ]; then
echo „$TOSEND“
cat „$TOSEND“||sendmail -t
fi
done
fi

done

Damit werden alle Mails erneut an den Mailserver übergeben und ausgeliefert.

Kann einem schon mal helfen, besser wär’s natürlich man kommt erst nicht in die Situation…!

Kategorien
Hardware

Linux und der Datalogic Gryphon GFS 4400 USB

Der Datalogic Gryphon GFS 4400 ist ein recht universeller Barcode Scanner der sich wunderbar in Produktionsanlagen verbauen lässt. Ich steuere ihn mit einem Linux Rechner und binde ihn nicht über die USB-Keyboard Schnittstelle an, sondern nutze die USV-COM Variante.

Per Default wird der Scanner laut Handbuch mit folgenden Einstellungen ausgeliefert:

RS-232: 9600,8,N,1,no handshaking,ACK/NAK disabled

Hier kommt die erste Hürde, das Datenblatt muss nach „stty“ übersetzt werden 🙂

Sobald der Scanner am System angeschlossen ist und auf USB-COM umgeschaltet wurde sieht man folgende Anzeige im Syslog:

Jul 18 15:25:33 e002110 kernel: [322458.030720] usb 1-9: new full-speed USB device number 37 using xhci_hcd
Jul 18 15:25:33 e002110 kernel: [322458.180222] usb 1-9: New USB device found, idVendor=05f9, idProduct=4204
Jul 18 15:25:33 e002110 kernel: [322458.180228] usb 1-9: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Jul 18 15:25:33 e002110 kernel: [322458.180232] usb 1-9: Product: Handheld Barcode Scanner
Jul 18 15:25:33 e002110 kernel: [322458.180236] usb 1-9: Manufacturer: Datalogic ADC, Inc.
Jul 18 15:25:33 e002110 kernel: [322458.180240] usb 1-9: SerialNumber: S/N G17AB1226
Jul 18 15:25:33 e002110 kernel: [322458.181927] cdc_acm 1-9:1.0: ttyACM0: USB ACM device

Der Scanner läuft also auf der Schnittstelle /dev/ttyACM0.

Mittels stty können jetzt die Kommunikationsparameter wie oben erwähnt eingestellt werden:

stty 9600 cs8 -cstopb -parenb ocrnl icrnl -F /dev/ttyACM0

Ein weiteres Problem das ich beim Einrichten hatte war dass der Scanner bei GS1-128 Barcodes den GS1 Code mit schickt – z.B. als Zeichen „+C1“ vor dem Barcode, das kann man abschalten indem man diese drei Barcodes scannt:

Wenn man jetzt via Bash Script die eingescannten Barcodes verarbeiten will, dann klappt das mit folgendem Befehl wunderbar:

head -n1 /dev/ttyACM0

In eine kleine „while“-Schleife verpackt und schon wird jeder eingelesene Barcode nach Wunsch verarbeitet.

Kategorien
Linux

rsync-Backup – jene Daten finden die gesichert wurden

Wer mit rsync und hardlinks Sicherungen erstellt hat eventuell das Problem dass er wissen möchte welche Daten sich zwischen zwei Sicherungen verändert haben, nicht jedes rsync-Backup Script protokolliert das bzw. verliert man bei 30 oder mehr Backups schon mal den Überblick.

Bei meiner Sicherung werden die einzelnen Sicherungen in Verzeichnissen mit der Bezeichnung daily.0 bis daily.30 gespeichert. In jedem Verzeichnis findet sich der Stand vom entsprechenden Tag von der letzten Sicherung die x-Tage zurückgerechnet.

Möchte man also wissen welche Datei gesichert wurde muss man jene finden die nur einen Hardlink besitzt, alle anderen wurden von einem der Vortage übernommen!

Hier hilft uns folgender Befehl:

find daily.2 -type f -links 1

Das „-links 1“ findet nur jene Dateien die einen einzigen Hardlink besitzen – ein Hardlink ist bei dieser Form der Sicherung das Minimum weil daily.0 und daily.1 ident sind und somit immer mindestens ein Link zum vorherigen Verzeichnis besteht.

 

Kategorien
Hardware Linux

Erste Gehversuche mit dem Raspberry PI – Zählen mit der Bash!

Letzte Woche ist das neue Versuchsobjekt – Raspberry PI angekommen und gestern hatte ich endlich mal ein wenig Zeit damit zu spielen!

Herausgekommen ist ein einfacher Zähler (via Taster), der mittels LED signalisiert dass er gedrückt wurde.

In Anlehnung an eine Bestehende Lösung bei uns im Hause habe ich das Ganze so gebaut dass der letzte Zählstand auch einen Neustart überlebt und manuell auf 0 gesetzt werden muss.

Da meine Erfahrung mit Python sehr gering ist, habe ich einfach mal die Bash bemüht und ein kleines Script gebastelt das erst den Pin 25 auf Eingang (kleiner schwarzer Taster in der Mitte) umschaltet und anschließend den Pin 24 auf Ausgang (grüne LED).

Dann wird eine Schleife gestartet welche auf eine Zustandsänderung reagiert (/sys/class/gpio/gpio25/value) und gleich die LED für kurze Zeit zum Leuchten bringt. Der aktuelle Zählerstand wird dann noch nach /var/tmp/counter1.txt gesichert und wieder von vorne begonnen.

Hier das kleine Script „counter.sh“:

#!/bin/bash

if [ -f „/var/tmp/counter1.txt“ ]; then
 anz=$(cat /var/tmp/counter1.txt)
fi

if [ ! -d „/sys/class/gpio/gpio25“ ]; then
 echo „25“ > /sys/class/gpio/export
fi

if [ ! -d „/sys/class/gpio/gpio24“ ]; then
 echo „24“ > /sys/class/gpio/export
fi

STATUS=$(cat /sys/class/gpio/gpio25/direction)
if [ „$STATUS“ == „out“ ]; then
 echo „in“ > /sys/class/gpio/gpio25/direction
fi

STATUS=$(cat /sys/class/gpio/gpio24/direction)
if [ „$STATUS“ == „out“ ]; then
 echo „out“ > /sys/class/gpio/gpio24/direction
fi

while true; do

 WERT=$(head -n 1 /sys/class/gpio/gpio25/value)

 if [ „$WERT“ != „$LASTWERT“ ]; then
  if [ „$WERT“ != „1“ ]; then
   anz=$((anz+1))
   echo $anz
   echo $anz > /var/tmp/counter1.txt
   echo 1 > /sys/class/gpio/gpio24/value
   sleep 0.01
   echo 0 > /sys/class/gpio/gpio24/value
  fi
 fi

 LASTWERT=$WERT

done

Nicht wirklich aufregend, aber dafür einfach und es macht genau das was es machen soll.
Schneller Lernerfolg, macht Lust auf mehr – da findet sich sicher noch eine Sinnvolle Aufgabe für das kleine Gerät…!

Cheat Sheet – Anschlußbelegung

Kategorien
Linux

Thunderbird – mehrere Mails aus dem Entwürfe Ordner gleichzeitig versenden

Folgende Problemstellung:

Beim Kunden läuft Thunderbird als Mailprogramm, die Buchhaltungssoftware (RZL) liefert frisch generierte Mahnungen als E-Mail im Entwürfe Ordner ab.

Leider besteht keine Möglichkeit direkt aus dem Entwürfe Ordner alle Mails auf einmal zu versenden, man muss jedes einzeln aufmachen und auf Senden klicken. Bei hunderten von Mahnungen kann das dann schon mal in Arbeit ausarten!

Wie üblich beschäftigt sich der Software Hersteller maximal mit dem Platzhirsch der Mailprogramme – ich bin aber schon mehr als froh dass überhaupt Mails an Thunderbird übergeben werden können, ist ja auch nicht selbstverständlich.

Wie kriegt man jetzt den Aufwand die hunderten Mahnungen zu versenden möglichst klein?

Die Lösung:

Im IMAP Postfach wird ein Ordner „AutoVersand“ erstellt, dort hin kann man aus dem Entwürfe Ordner alle Mails einfach verschieben.

Am Server läuft dann ein kleines Script welches alle Mails die in dem Ordner landen automatisch abarbeitet und per sendmail verschickt. Fertig!

Viel einfacher geht es eigentlich nicht mehr 🙂

Hier noch das Script welches vom cron-Daemon aufgerufen wird und die Mails verschickt:

#!/bin/bash

send_mail() {
 OK=$(cat $EMAIL|sendmail -t 2>&1)
 if [ „$OK“ ]; then
  logger -t autoversand „Fehler beim Versenden! ($OK||$EMAIL)“
 else
  SORDNER=$(echo $EMAIL|sed -e „s/AutoVersand/Sent/g“)
  mv $EMAIL $SORDNER
 fi
}

for EMAIL in $(ls /srv/imap/domain.tld/*/.AutoVersand/cur/* 2>/dev/null); do
 send_mail
done

Kategorien
Linux

Linux – top – hohe „wa“ Werte, welcher Prozess wartet da?

Wer bei „top“ unter Linux  feststellt dass Prozesse auf IO-Zugriffe warten müssen, den interessiert es meist um welche Prozesse es sich dabei handelt…

Ein einfacher weg das heraus zu finden ist der folgende:

watch -n 1 „(ps aux | awk ‚$8 ~ /D/  { print $0 }‘)“

Die erscheinenden Prozesse warten darauf eine IO-Zugriff ab zu schließen.
Das Filtern nach „D“ in der Prozess Status Spalte liefert uns die passenden Prozesse, jene Prozesse mit „+“ nach dem D sind Vordergrundprozesse und laufen somit auf einer Konsole, die genauere Bedeutung der Werte liefert „man ps“.

Kategorien
Linux

Linux – Benutzerrechte von Ordner zu Ordner transferieren

Es kann vorkommen dass man einen PC neu aufsetzt und anschließend ein Backup der Konfigurationsdateien einspielen möchte.

Dabei kann es zu dem Prolbem kommen dass am alten System die UID’s der Benutzer andere Nummern hatten als am neuen System.

In meinem Beispiel wollte ich das /etc Verzeichnis von einem Backup auf einem frisch installierten Server einspielen, aber z.B. /etc/bind hatte auf dem alten System eine andere UID.

Fertiges Tool ist mir keines bekannt gewesen und bei rsync kann man zwar genau wie bei cp die Berechtigungen mit übernehmen, allerdings habe ich keinen Schalter gefunden der lediglich die Berechtigungen übernimmt.

Also musste die Bash wieder mal herhalten 🙂

Das copy_permission.sh Script sieht wie folgt aus:

#!/bin/bash

if [ ! „$1“ ]; then
 echo „Bitte Original-Verzeichnis angeben“
 exit
else
 if [ ! -d „$1“ ]; then
  echo „Original-Verzeichnis existiert nicht!“
  exit
 fi
 DIRVON=$1
fi

if [ ! „$2“ ]; then
 echo „Bitte Ziel-Verzeichnis angeben“
 exit
else
 if [ ! -d „$2“ ]; then
  echo „Ziel-Verzeichnis existiert nicht!“
  exit
 fi
 DIRNACH=$2
fi

cd $DIRVON

for F in $(find . -print); do

 OCT=$(stat „$F“|sed  -n -e 4p|cut -f2 -d“ „|cut -b 2-5)
 BENUTZER=$(stat „$F“|sed  -n -e 4p|cut -b40-47|sed -e „s/ //g“)
 GRUPPE=$(stat „$F“|sed  -n -e 4p|cut -b64-71|sed -e „s/ //g“)

 chmod $OCT „$DIRNACH/$F“
 chown $BENUTZER:$GRUPPE „$DIRNACH/$F“

done

Ein einfacher Aufruf von „copy_permission.sh /etc /tmp/etc“ übernimmt alle Benutzer und Berechtigungen aus dem /etc Verzeichnis und überträgt sie nach /tmp/etc.

Das Ding ist sicher nicht perfekt, für mich hat’s aber funktioniert – quick and dirty also 🙂

Kategorien
Linux

Mal eben schnell einen seriellen Barcode Leser (Metrologic Orbit) mit Linux auslesen

Manche Sachen sind im Grunde so einfach dass man sich echt wundern muss warum man im Internet so wenig darüber findet!

Einen Barcode Leser der Firma Metrologic – Type Orbit MS7120 – mit Linux zu Testzwecken mal eben auslesen fällt definitiv in diese Kategorie 🙂

#!/bin/bash

stty 19200 cs8 -parenb crtscts -echo -F /dev/ttyS0

while true; do

 BARCODE=$(head -n 1 /dev/ttyS0)

 # und hier was auch immer man damit anstellen möchte…
 echo „$BARCODE“

done

Das kleine Bash Script stellt erst mal die serielle Schnittstelle korrekt ein um anschließend immer je eine Zeile einzulesen und zu verarbeiten.

In dem Fall werden die Daten einfach per echo ausgegeben, allerdings kann man damit alles Mögliche anstellen – z.B. in eine Datenbank schreiben.

Kategorien
Linux

Kleine Wunschliste an ALLE Software Projekte (Windows)

Unter Linux hat man das Problem ja eigentlich nicht wirklich, da kümmern sich die Distributoren ja recht zuverlässig um Aktualität und Sicherheitsupdates der Software – will man was Neues macht man einfach ein Upgrade.

Bei Windoof schaut das ganze ein klein wenig anders aus – z.B. Java, wer Java installiert hat, dem meldet Java selbst wenn eine neue Version verfügbar ist. Allerdings nützt das einem normalen Anwender wenig wenn der das Update dann nicht installieren kann weil ihm die Rechte dazu fehlen und viel Spaß jenen Admins die von jedem einzelnen Anwender angerufen und über ein fehlendes Update informiert werden 🙂

Was tut man also dagegen? Man versucht die Installation möglichst zu automatisieren – im Idealfall sogar den Download des Updates und auch die komplette Verteilung der Software.

Nur machen es einem die Hersteller da nicht immer ganz einfach – am Beispiel JAVA z.B. findet sich die aktuell installierte Version in der Registry unter folgendem Key:

„HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionInstallerUserDataS-1-5-18Products4EA42A62D9304AC4784BF238120612FFInstallProperties“ – „DisplayVersion“

Dort steht dann „6.0.210“ als Version vermerkt.

Ruft man Java mit dem Parameter „-version“ auf bekommt man auch die aktuell installierte Version genannt, dort lautet das Ganze dann allerdings wie folgt:

java version „1.6.0_21“
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) Client VM (build 17.0-b17, mixed mode, sharing)

Man könnte sich natürlich jetzt aus 1.6.0_21 ein 6.0.210 zusammenbasteln, aber wer garantiert dass bei der nächsten Auslieferung sich nicht das Schema ein wenig verändert und nichts mehr zusammenpasst?

Hinzu kommt noch dass man auf der Webseite des Herstellers nicht wirklich einen zuverlässigen Link zur letzten Version findet – normalerweise würde ich erwarten (viele OpenSource Projekte machen das so vor) dass sich ein Link auf die „latest version“ findet, der direkt zur aktuellen Version zeigt.

Mit Nichten, bei Java kann man das ganze zwar über die Webseite recht schön abrufen – aber für eine Automatisierung ist das Ganze nicht wirklich geeignet, eventuell gibts ja irgendwo einen immer gleichen Link zur aktuellen Version – nur scheint der nirgends dokumentiert zu sein oder nur einem auserlesenen Kreis von Menschen zur Verfügung zu stehen.

Mein Wunsch an ALLE Softwarehersteller wäre also folgende kurze Liste:

1) eine Webseite auf der immer zur aktuellen Version verlinkt ist
2) ein Versionierungsschema das sowohl auf der Webseite wie auch sonst überall identisch ist
3) einen Installer der die Software auch silent installieren kann und gut dokumentiert ist
4) der Installer sollte sich auch gleich um veraltete Versionen kümmern (Switch)
5) leicht zu findender Versionseintrag in der Registry oder im Programmordner für den man keinen Kryptologen braucht
6) ein Uninstaller der auch silent ohne Rückfragen durchlaufen kann

Das wär’s eigentlich auch schon – damit könnte man wunderbar z.B. via Kix Script einen Installer zusammenbauen der sich dann darum kümmert dass Software möglichst immer aktuell bleibt.

Hier mal ein Beispiel für 7-Zip:

Bash Script zum herunterladen der aktuellen Version

#!/bin/bash

# pfadangaben
ZIPDIR=“http://www.7-zip.org/“
TARGETDIR=“/srv/samba/sw“
INSTZIPFILE=“/srv/samba/sw/zip.version“
ORIGKIX=“/srv/samba/netlogon/sw/zip.orig“
NEWKIX=“/srv/samba/netlogon/sw/zip.kix“

# aktuell installierte version ermitteln
if [ -a „$INSTZIPFILE“ ]; then
INSTZIP=$(cat $INSTZIPFILE)
fi

# aktuell online verfügbare version ermitteln
ZIPPVERSION=$(w3m -dump „$ZIPDIR“|grep „Download 7-Zip „|grep -v beta|awk -F’Download 7-Zip‘ ‚{print $2}’|awk ‚{print $1}‘)
ZIPVERSION=$(echo $ZIPPVERSION|sed -e „s/.//g“)
ZIPNAME=“http://downloads.sourceforge.net/sevenzip/7z$ZIPVERSION.exe“

ZIPFILENAME=“7z$ZIPVERSION.exe“

# wenn versionen unterschiedlich sind download starten
if [ ! „$INSTZIP“ == „$ZIPVERSION“ ]; then
wget -q -O „$TARGETDIR/$ZIPFILENAME“ „$ZIPNAME“
if [ -s „$TARGETDIR/$ZIPFILENAME“ ]; then
# heruntergeladene versionsnummer speichern
echo $ZIPVERSION > $INSTZIPFILE
# kix-script auf den aktuellen stand bringen
cp $ORIGKIX $NEWKIX
sed -i -e „s/VERSION/$ZIPPVERSION/g“ $NEWKIX
sed -i -e „s/DATEINAME/$ZIPVERSION/g“ $NEWKIX
fi
fi

Das dazu passende Kix-Script bzw. die Vorlagedatei

; 7zip installieren bzw pruefen
$ISINST = READVALUE(„HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionUninstall7-Zip“,“DisplayName“)
IF „$ISINST“ = „7-Zip VERSION“
? „7Zip|ist installiert $ISINST“
ELSE

? „7Zip|wird installiert – VERSION“
SHELL „\SERVERPFAD7zDATEINAME.exe /S /D=C:Programme7-Zip“

ENDIF

Das ganze muss man dann nur noch am Windows Rechner so einbinden dass das Kix-Script als Administrator ausgeführt wird, sehr gut eignet sich dafür ein geplanter Task der beim Starten des Rechners ausgeführt wird.