Dokumenten-Management-System (DMS) für Linux - Dokumenten-Archivierung (simplex, duplex) im Eigenbau

Jeder kennt sicherlich das Problem: nahezu täglich landen per Post neue Unterlagen ins Haus. Versicherungsschreiben, Rechnungen, Vertragsunterlagen, Lohnabrechnungen sind nur einige Beispiele, welche die heimischen DIN-A4-Ordner füllen. So sammelt sich mit der Zeit eine Menge Papierkram an und eine etwaige Suche nach einem bestimmten Dokument endet oftmals in einem hektischen Blättern in den DIN-A4-Ordnern. Man könnte die Ordner regelmäßig aussortieren, aber woher soll man wissen, dass man die Dokumente später nicht doch noch einmal benötigen wird?

Dokumenten-Management-System im Eigenbau: Archivieren unter Linux

Die perfekte Lösung ist ein Dokumenten-Management-System (kurz DMS): man scannt die Dokumente zusätzlich ein und archiviert diese als GIF, TIF, PDF oder einem anderem Dateiformat. Die Vorteile liegen klar auf der Hand: zum einen erleichtert es die spätere Recherche, da man am PC die Dokumente einfach durchsuchen kann, und zum anderen fällt einem die Entscheidung leichter, sich von bestimmten Dokumenten zu trennen. Notfalls kann man auf das archivierte Dokument zurückgreifen. Wer rigoros ist, verzichtet sogar komplet auf das Papierdokument und wirft dieses nach dem Archivieren direkt in den Papierkorb.

Und ein weiterer wichtiger Aspekt beim Archivieren mithilfe eines Dokumenten-Management-Systems ist die Möglichkeit, ein Backup der Dokumente zu erstellen. Der Ärger und die Kosten sind groß, wenn beispielsweise aufgrund eines Hausbrandes sämtliche Unterlagen vernichtet werden. Hat man aber die Dokumente regelmäßig archiviert und die Daten liegen nach einem solchen Vorfall beispielsweise bei den Eltern an einem sicheren Ort, ist der Verlust der Originalunterlagen zu verschmerzen!

In diesem Artikel wird gezeigt, wie man unter Linux Dokumente automatisiert und strukturiert archivieren kann. Die archivierten Dokumente sollen mit einer ausreichenden Qualität eingescannt, in vorgegebenen Verzeichnissen abgelegt und chronologisch gespeichert werden. Der Aufwand für den Anwender soll möglichst gering sein, so dass die Archivierung völlig autonom durchgeführt wird. Des Weiteren wird gezeigt, wie man mit ein paar Tricks auch doppelseitig gedruckte Dokumente (Duplex) mit einem einfachen Einzugscanner (Simplex) einscannen kann. Ziel dieses Artikels ist es also, ein einfaches und kostenloses Dokumenten-Management-System für den Hausgebrauch zu entwickeln, ohne viel Geld in teure Hardware oder Software zu entwickeln.

Gleichzeitig zeigt dieser Artikel die hervorragenden Möglichkeiten des Bash-Scripting, wie man eine solche Problemstellung lösen kann. Linux-Anwender, welche ggf. ihr Bash-Scripting Wissen erweitern möchten, sollten diesen Artikel ebenfalls aufmerksam lesen.

Voraussetzungen, Ist-Zustand, Anforderungen

Für die Archivierung benötigt man lediglich einen handelsüblichen Scanner. Einzige Voraussetzung des Scanners ist ein Stapeleinzug (ADF, Automatic Document Feeder = automatischer Originaleinzug), damit man mehrere Dokumente nacheinander einscannen kann. Dieser Scanner sollte unter Linux (bsp. Sane Projekt) lauffähig sein. Ein herkömmlicher Flachbettscanner ist für die Archivierung nicht geeignet. In diesem Artikel wird ein HP OfficeJet 5610 eingesetzt, der zwar einen solchen Stapeleinzug besitzt, aber nur einseitig (simplex) einscannt. Später wird gezeigt, wie man trotzdem doppelseitige Dokumente problemlos einscannen kann.

Die eingescannten Dokumente werden in vorgegebene Verzeichnisse (bsp. Haftpflicht, KFZ-Versicherung, Miete, Beruf, usw.) mit einem entsprechenden Namen gespeichert. Die Nummerierung ist vierstellig und fortlaufend, so dass man die Dokumente chronologisch archiviert.

HP OfficeJet 5610 mit Stapeleinzug
HP OfficeJet 5610 mit Stapeleinzug
Verzeichnisstruktur für Archivierung
Verzeichnisstruktur für Archivierung

Das sind die Anforderungen an das DMS bzw. an die Archivierung:

  • Vordefinierte Menüpunkte für Dokumententyp (bsp. Haftpflicht, KFZ)
  • Dokumente sollen automatisch und chronologisch in die Verzeichnisse einsortiert werden
  • Einseitig als auch Doppelseitig bedruckte Dokumente können eingescannt werden
  • Dateityp: GIF, Farbe, 150dpi
  • Umsetzung mittels Linux Bash Scripting

Umsetzung des Dokumenten-Management-Systems unter Linux

Beginnen wir mit unserem Projekt. An dieser Stelle sollte der Scanner installiert sein und jeder in der Lage sein, Dokumente per Befehlszeile einzuscannen. Auch die entsprechenden Optionen des Scanners sollten bekannt sein. Um den hier eingesetzten HP OfficeJet 5610 unter Linux lauffähig zu machen, benötigt man die HPLIP-Treiber und die Kernelmodule USB, parport, lp, partport_pc. Mit folgendem Befehl werden Dokumente per Stapeleinzug eingescannt:

# manueller Scan
hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf

War der manuelle Scan erfolgreich, erstellen wir nun unser Skript namens scan.sh, speichern es ab und machen es mittels chmod +x scan.sh ausführbar.

# Auszug scan.sh

#!/bin/bash
# Scannen (Document Management System)
# Copyright PC-Erfahrung.de
# 15/10/2010

###############
# Variables
##############

pathtmp="/tmp/scannen/"
pathmain="/home/chef/dms"

# Array: text for start screen
text=(
"Bank"
"Miete - Strom"
"Versicherung kfz"
"Versicherung rentenversicherung"
)

# Array: path where documents are stored depending on pathmain
path=(
"banken/sparkasse"
"miete/strom"
"versicherungen/kfz"
"versicherungen/rentenversicherung"
)

# Array: name of documents
fileprefix=(
"sparkasse-"
"strom-"
"vrs-kfz-"
"vrs-rentenversicherung-"
)

Wir beginnen mit der Definition von bestimmten Variablen, welche Informationen über Speicherort, Dateinamen, etc. enthalten. Die Variable pathmain enthält den absoluten Pfad zu unseren Verzeichnissen, in denen die Dokumente gespeichert werden. Es stellt quasi das Root-Verzeichnis unseres DMS dar. pathtmp hingegen ist das temporäre Arbeitsverzeichnis.

Darauf folgen die drei Arrays text, path, fileprefix. text ist der Anzeigename in unserem Startscreen bzw. dem Auswahlmenü, welcher beliebig gewählt werden kann. path ist der relative Pfad zum Speicherort, welcher abhängig von pathmain ist. Im ersten Beispiel werden also die Dokumente in /home/chef/dms/banken/sparkasse abgelegt. Zu guter Letzt noch fileprefix, welcher den Dateinamen enthält. Auch hier wieder das erste Beispiel: alle Dokumente werden als sparkasse-1000.gif, sparkasse-1001.gif, sparkasse-1002.gif, usw. gespeichert. Die drei Arrays können problemlos erweitert werden. Man muss lediglich die Reihenfolge der Zeilen beachten, damit nicht etwas von der Sparkasse in der KFZ-Versicherung landet.

Anhand dieser Informationen können wir nun den Startscreen unseres Skriptes erstellen:

# Auszug scan.sh

################
# start screen
################

echo ""
echo "+++++++++++ Waehle Archiv ++++++++++++"

# Info: ${#text[*]} = Anzahl der Elemente im Arry
for ((i=0; i<${#text[*]}; i++))
do
    echo -n "[$i] "
    echo ${text[$i]}
done

echo -n "Auswahl > "
read choice

Erklärung: das Ziel ist, alle Elemente unseres Array text auszulesen, um diese dann anzuzeigen. Hierfür wurde eine FOR-Schleife erstellt, welche bei 0 zu zählen beginnt (i=0) und bei der Gesamtzahl der Array-Elemente stoppt. Die Gesamtanzahl eines Arrays erhält man mit dem Ausdruck ${#meinArray[*]}.Der Vorteil dieser Umsetzung ist, dass das Array beliebig erweitert werden kann, ohne später Eingriffe in den Code vornehmen zu müssen.

Anschließend geben wir Element für Element den Text aus und fordern anschließend den Anwender auf, die entsprechende Zahl einzugeben. Dies tut man mittels read, welches Tastatureingaben auswertet. Die Eingabe des Anwenders wird in der Variable choice gespeichert:

Linux Dokumenten-Management-System: Auswahlmenü

Nun kommt der interessante Teil unseres kleinen Programms. Nachdem der Anwender seine Auswahl getroffen haben, wissen wir, in welchem Verzeichnis die Dokumente abgelegt werden. Nehmen wir als Beispiel [2] Versicherung kfz. Laut unserer Variablendefinition liegen die Dokumente unserer KFZ-Versicherung im Verzeichnis /home/chef/dms/versicherungen/kfz/:

# ls -1 /home/chef/dms/versicherungen/kfz/
vrs-kfz-1001.gif
vrs-kfz-1002.gif
vrs-kfz-1003.gif
vrs-kfz-1004.gif
vrs-kfz-1005.gif

Als nächstes müssen wir herausfinden, welches die höchste Zahl im Augenblick ist (1005, vrs-kfz-1005.gif), damit wir die neu hinzugekommenen Dokumente einreihen können. Hierfür müssen wir die folgenden vier Zeichen nach vrs-kfz- (gespeichert in der Variablen fileprefix) analysieren:

# Auszug scan.sh

################
# program
################

# Get length of fileprefix
fileprefix_length=$(echo ${fileprefix[$choice]} | awk '{print length}')

cd $pathmain/${path[$choice]}/

# Get highest number in folder
highest_number=$(ls -1 ${fileprefix[$choice]}* | tail -n1 | cut -c"$((fileprefix_length+1))-$((fileprefix_length+4))")

Zuerst werten wir die Zeichenlänge unseres fileprefix (vrs-kfz-) aus. Erstmals greifen wir auf das Array-Element zu, welches von der Eingabe des Anwenders (choice) abhängig ist. Das Array lautet fileprefix, so dass die Syntax wie folgt lautet: ${fileprefix[$choice]}

In eckigen Klammern steht also der Index, sprich die Zahl, welcher der Anwender eingegeben hat. Wir geben den fileprefix nun mit echo aus und werten die Zeichenlänge mit awk aus. Gespeichert wird das ganze in der Variablen fileprefix_length. Wir haben nun die Zeichenlänge unseres fileprefix.

Im nächsten Schritt müssen folgende Dinge gemacht werden: 1.) Dateinamen mit der höchsten Nummer finden und 2.) Dateinamen zerlegen. Hierfür verwenden wir die Standard-Linux-Programme ls, tail und cut und speichern das Ergebnis in der Variablen highest_number. Hier die Erläuterung:

  • ls -1 ${fileprefix[$choice]}* = Zeige alle Dateien mit dem Dateinamen vrs-kfz- an
  • tail -n1 = Zeige nur eine Zeile an (dies entspricht der zuletzt angezeigten Zeile, welches der Dateiname mit der höchsten Zahl ist)
  • cut -c"$((fileprefix_length+1))-$((fileprefix_length+4))" = schneide die vier Zeichen beginnend bei der Zeichenlänge + 1.

Prima! Mit etwas logischen Nachdenken und strukturierter Vorgehensweise haben wir nun in der Variable highest_number die Nummer (1005) der zuletzt archivierten Datei gespeichert. Mit diesen Informationen können wir nun mit dem Scannen beginnen.

Einseitig bedruckte Dokumente (simplex) archivieren

Beginn wir mit dem einfachen Weg, nämlich einseitig bedruckte Dokumente:

    # ###### SCANNEN ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf
   
    counter=$[highest_number+1]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+1]
    done

Zuerst werden die Dokumente mit dem Standardnamen in das temporäre Verzeichnis eingescannt. Man findet also folgende Dokumente vor: hpscan001.jpg, hpscan002.jpg, hpscan003.jpg, usw. vor. Anschließend erhöhen wir highest_number um 1, da wir ansonsten das zuletzt gespeicherte und archivierte Dokument überschreiben würden (counter=$[highest_number+1]). 

In der darauf folgenden FOR-Schleife werden alle Dokumente beginnend mit hp verarbeitet. Zuerst optimieren wir das eingescannte Bild mittels convert: 16 Farben sollten ausreichen und GIF als Dateityp ist für Dokumente besser geeignet. In derselben Zeile erhält das neu erstellte GIF auch gleich den passenden Namen:

  • ${fileprefix[$choice]} = entspricht vrs-kfz-
  • $counter = entspricht 1006

So lautet der Dateiname vrs-kfz-1006.gif. Anschließend wird die Datei von dem temporären Verzeichnis in das entsprechende Verzeichnis verschoben ($pathmain/${path[$choice]}/ = /home/chef/dms/versicherungen/kfz/). Der Counter wird abschließend um 1 erhöht, damit das nachfolgende Dokument vrs-kfz-1007.gif lautet.

Beidseitig bedruckte Dokumente (Duplex) archivieren

An dieser Stelle muss getrickst werden, denn der HP OfficeJet 5610 besitzt keine Duplex-Einheit und kann somit nur einseitig einscannen. Es werden demzufolge zwei Scandurchgänge benötigt. Im ersten Schritt werden die ungeraden Dokumente eingescannt, um zweiten Schritten die geraden Seiten. Abschließend muss die Nummerierung angepasst werden, so dass die Dokumente richtig sortiert werden.

In unserem Bash-Skript wurde diese Vorgehensweise wie folgt umgesetzt:

    # ###### SCANNEN 1 ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf
   
    counter=$[highest_number+1]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+2]
    done

    rm -f hp*   
   
    echo "++++++++ Duplex: 2. Scandurchgang"
    echo -n "Bitte Blaetter wenden!"
    read abc
   
    # ###### SCANNEN 2 ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf   
   
    counter=$[highest_number+2]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+2]
    done   

Das Prinzip ist identisch zum einseitigen Scan. Der entscheidende Unterschied liegt beim counter, der nicht mit 1, sondern mit 2 hochgezählt wird (counter=$[$counter+2]). Im ersten Scandurchlauf erhalten wir folgende Dokumente:

vrz-kfz-1005.gif
vrz-kfz-1007.gif
vrz-kfz-1009.gif
usw...

Im zweiten Scandurchlauf wird der counter ebenfalls um 2 erhöht, wichtig aber ist, dass der Start-Counter bereits um zwei erhöht wurde (counter=$[highest_number+2]). Somit startet der zweite Scandurchgang mit vrz-kfz-1006.gif, und nicht mit vrz-kfz-1005.gif. Wir erhalten also folgende Dokumente:

vrz-kfz-1006.gif
vrz-kfz-1008.gif
vrz-kfz-1010.gif
usw...

Das war es eigentlich schon und unser Duplex-Manuell-Scan sowie das ganze Dokumenten-Management-System ist funktionsfähig. Mit einfachen Mitteln und Standard-Linux-Programmen erhält man einfach zu bedienendes Archivierungssystem,

Start: Auswahlmenü
Start: Auswahlmenü
1. Scandurchgang (Beispiel Duplex)
1. Scandurchgang (Beispiel Duplex)
2. Scandurchgang
2. Scandurchgang
Abschluss mit Übersicht
Abschluss mit Übersicht

Der komplette Code des DMS

#!/bin/bash
# Scannen (Document Management System)
# Copyright PC-Erfahrung.de
# 15/10/2010

###############
# Variables
##############

pathtmp="/tmp/scannen/"
pathmain="/home/chef/dms"

# Array: text for start screen
text=(
"Bank"
"Miete - Strom"
"Versicherung kfz"
"Versicherung rentenversicherung"
)

# Array: path where documents are stored depending on pathmain
path=(
"banken/sparkasse"
"miete/strom"
"versicherungen/kfz"
"versicherungen/rentenversicherung"
)

# Array: name of documents
fileprefix=(
"sparkasse-"
"strom-"
"vrs-kfz-"
"vrs-rentenversicherung-"
)

################
# start screen
################

echo ""
echo "+++++++++++ Waehle Archiv ++++++++++++"

# Info: ${#a[*]} = Anzahl der Elemente im Arry
for ((i=0; i<${#text[*]}; i++))
do
    echo -n "[$i] "
    echo ${text[$i]}
done

echo -n "Auswahl > "
read choice

################
# program
################

# Get length of fileprefix
fileprefix_length=$(echo ${fileprefix[$choice]} | awk '{print length}')

cd $pathmain/${path[$choice]}/

# Get highest number in folder
highest_number=$(ls -1 ${fileprefix[$choice]}* | tail -n1 | cut -c"$((fileprefix_length+1))-$((fileprefix_length+4))")

echo ""
echo "+++++++++++ Waehle Scan-Mode ++++++++++++"
echo "[0] Simplex"
echo "[1] Duplex"
echo -n "> "
read choice_scan

# check temp folder
if [ -d $pathtmp ]
then
    echo "Temp-Verzeichnis vorhanden"
else
    echo "Erstelle $pathtmp"
    mkdir $pathtmp
fi

cd $pathtmp

if [ $choice_scan -eq 1 ]
then
    clear
    echo "++++++++ Duplex: 1. Scandurchgang"

    # ###### SCANNEN 1 ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf
   
    counter=$[highest_number+1]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+2]
    done

    rm -f hp*   
   
    echo "++++++++ Duplex: 2. Scandurchgang"
    echo -n "Bitte Blaetter wenden!"
    read abc
   
    # ###### SCANNEN 2 ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf   
   
    counter=$[highest_number+2]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+2]
    done   
   
else
    clear
    echo Simplex

    # ###### SCANNEN ###### #
    sudo hp-scan --res=150 --size=a4 --compression=jpeg --mode=color --adf
   
    counter=$[highest_number+1]
    for i in $(ls -1 hp*)
    do
        convert -colors 16 $i ${fileprefix[$choice]}$counter.gif
        mv ${fileprefix[$choice]}$counter.gif $pathmain/${path[$choice]}/
        counter=$[$counter+1]
    done
fi

rm -f hp*

################
# debug
################

ls -l $pathmain/${path[$choice]}

echo -n "name = "
echo ${text[$choice]}

echo -n "path = "
echo -n $pathmain/
echo ${path[$choice]}

echo -n "prefix = "
echo ${fileprefix[$choice]}

echo -n "Highest_number = "
echo $highest_number