Jira Upgrade von 4.3.3 auf 5.x

Posted in c0de on June 7th, 2013 by serge

Viele Software Unternehmen verwenden Jira, um ihre Aufgaben, Fehler, Verbesserungswünsche (Tasks, Bugs, Improvents) ihrer Software festzuhalten. Es ist eine nette Platform, in der man unter anderem durch Zusatz diverser Add-ons die Entwicklung planen und den Fortschritt messen bzw. graphisch darstellen kann.
Pie Chart
Das interessanteste ist jedoch, daß man jeden Entwicklungsschritt für jedes Unternehmen individuell konfigurieren kann.

Möchte jemand zum Beispiel zu den Bearbeitungsschritten eines Fehlers zusätzlich zu den Stati “Offen”, “In Arbeit” und “Entwickelt” einen “Test” Status haben (den Arbeitsablauf der Entwicklung ein wenig modifizieren), dann bitte, einfach konfigurieren. Möchte jemand bei den einzelnen Bearbeitungsschritten zusätzlich eine Priorität angeben können, dann bitte, einfach ein neues Feld (“Custom Field”) hinzufügen und evtl. einen Standardwert setzen.

Hier ist das Problem

Und hier ist schon das Problem. In der Jira Version 4.3.3 ist das Datenbank Modell noch stark ausbaufähig, Primärschlüssel sind die dahinterliegenden Werte anstatt fortlaufenden Nummern. Der voreingestellte Wert des “Custom Fields” wird in eine genericconfiguration-Tabelle als Fremdschlüssel in XML-Notation mit Variablentypvorgabe geschrieben, z.B. beim Feld Priorität wird der Wert “astronomisch hoch” als “astronomisch hoch” eingetragen.

Ab Jira Version 5 hat man diesen Mangel teilweise erkannt und ebenso teilweise behoben. Jede Tabelle hat einen ordentlichen Primärschlüssel bekommen. Jetzt fragt sich der geneigte Leser: “Wieso denn teilweise?” Na weil hier und da das Fremdschlüssel-Feld immer noch den Typ String hat und die Fremdschlüssel werden nach wie vor in XML-Notation wie z.B. wie folgt reingeschrieben: “12203“. Schlimm genug, daß man es mit Java programmieren mußte, der Sprache, durch deren JVM Overhead jedes Programm ausgebremst wird, und die Platformunabhängigkeit suggeriert. Klar, “Hello World” läuft überall. Jedoch was ist mit dem Big und Small Endian? Sei es drum, wenn man kein C kann, kann man kein C. Es ist einfacher und schneller beim Programmieren. Außerdem ist es schön, wenn man einen Garbage Collector hat und man sich nicht selbst ums Aufräumen kümmern muß. Blöd nur, daß wenn man nicht all zu genau hinschaut, es wohl sogar recht sauber aussieht und man dazu schnell tendiert alle unangenehmen Sachen, die bei C zu Core Dump führen, die JVM machen zu lassen. Man muß es nicht selbst machen, mehr braucht man nicht zu erwarten.

Richtiges Datenbank Modell bitte?

Wenn man schon Java benutzen muß, hätte man ein richtiges Datenbank Modell schon der Performance wegen erstellen können. Einen String jedes Mal zu lesen, zu zerlegen und den Feldtyp zu erkennen dauert im Betrieb jedes Mal sehr viel länger als einfach einen richtigen Feld-Typ zu erwarten. Ja, es kostet mehr Entwicklungsaufwand, weil die Entwickler plötzlich eine richtige Architektur haben, viele kostspielige Fehler der Vergangenheit ausbügeln UND plötzlich aus ihrem Kämmerchen herauskommen und mit anderen Entwicklern arbeiten müssen. Und ja, es muß bis in die Untiefen der Software getestet werden! Ja und? Ihr wollt doch keinen ungetesteten Blödsinn verkaufen, oder?!? Jede “schnell-schnell” und/oder “ist nur mal zum testen und plötzlich in Produktion” Aktion, jeder nicht sofort begradigte Fehler kostet das Unternehmen im Nachhinein das Vierfache!

Nun ja, wie mannigfaltig die Gründe auch sein können eine richtige Architektur zu entwickeln bzw. die alte zu verbessern, die Weisen aller Weisesten bei Atlassian wussten es einfach besser. Es ist immerhin eine Verbesserung zu vorher, eventuell kommt die Einsicht noch.

Hail to usability improvements!

Wirklich schön ist, daß man im Zuge des Upgrade Prozesses daran gedacht hat alle Jira-eigenen Tabellen so zu modifizieren, daß alle Fremdschlüssel zu den neuen Primärschlüsseln passen (Es klappt nicht immer, einen Clone der Jira Instanz mit der alten Version zu haben ist goldwert. Für Upgrade Versuche sowieso. Hail to the Jira-Clone!). Soweit so gut, Upgrade von Version 4.3.3 auf Version 5.x (in meinem Fall Jira Version 5.2.5) verläuft problemfrei. Jira kommt sogar hoch, man kann sich im neuen und schönen System wunderbar bewegen, die vielen neuen sehr sinnvollen und lange vermissten Verbesserungen, von denen man manchmal sogar selbst nicht wußte, daß man sie dringend braucht, ausprobieren. Die Konfiguration der Projekte, Felder usw. ist deutlich einfacher und schöner. Usability++

Upgrade tut so als ob alles glatt lief

Das geht alles so lange gut, bis man versucht sich eine neue Aufgabe bzw. einen neuen Task anzulegen. Man füllt alle Felder aus, überdenkt sie und klickt dann auf “Create”. Und nichts passiert. Absolut gar nichts. In den Log-Dateien wird sich über den unverschämten Versuch aufgeregt einen String-Datentyp als Long-Datentyp auszugeben. Was? Woher? Weniger Aussagekraft kann man einer Fehlermeldung nicht zuweisen? Was ist das? Ist das Python mit den sinnlosesten Fehlermeldungen überhaupt oder was?!? Weiß denn keiner wie man einen sinnvollen “catch” in einem try-catch Block schreibt?!? Tja, nachdem man sich etwas beruhigt hat und das Hirn wieder anfängt zu arbeiten, fragt man sich was nun?

Man fragt selbstverständlich das FAQ der Atlassian Seite. Es sagt Dir nur: “Ja, sieht nach einem Custom Field aus, da musst es in der Datenbank suchen und da was löschen”. Voller Entsetzen schaust Du Dir Deine zwei Milliarden selbst erstellte Felder an, fängst an zu zucken und fällst fast in Ohnmacht. Ja, welches denn? Kann man den Störenfried nicht einfach so identifizieren und zu Mitarbeit zwingen? Kann jawohl nicht wahr sein! Hätte man das nicht gleich bei der Datenbank Modifikation im Zuge des Upgrade Prozesses korrigieren können?!? Bei allen anderen Feldern wurde es ja ebenfalls gemacht!

Die Lösung

Um ehrlich zu sein, man kann! Aber warum muß ich die Lösung finden, obwohl ich damit nichts zu tun habe?

delete from genericconfiguration 
where datakey in (select id 
                  from fieldconfiguration 
                  where fieldid like 'customfield%');

Nachtrag

Ok, so sanft ist das Upgrade doch nicht verlaufen. Recht viele customfieldoption Felder haben immer noch einen String-Primärschlüssel aus der vorherigen Jira Version anstatt eines richtigen Primärschlüssels. Wieso ist das Feld eigentlich immer noch ein varchar-Feld, wenn da nur Fremdschlüssel stehen müßten? Ah, verstehe, weil man die Migration sauber durchführen müßte. :-/

Goldbachsche Vermutung – 3

Posted in c0de on May 28th, 2012 by serge

Eines wunderschönen Mittags unterhielt ich mich mit DEM Meisterprogrammierer und Architekt unserer Firma, Harmen, bezüglich der Prüfung der ungeraden Zahlen auf Primeigenschaften. Seine Idee war, daß ich die ungeraden Zahlen nur gegen die bereits errechneten Primzahlen prüfen müßte. Und da hat er Recht!

Jede andere ungerade Zahl (keine Primzahl) wäre doch eigentlich nur noch der Multiplikator zweier Primzahlen. Das ist doch schon mal ausgezeichnet, weniger Zahlen zum durchlaufen. Bei 1000 Zahlen sind es anstatt 499 nur noch 168, bei einer Million nur noch 78498. Perfekt!

Wenn man das jetzt weiter denkt, könnte man argumentieren, daß man nur gegen Primzahlen prüfen sollte, die maximal die Quadratwurzel der zu prüfenden ungeraden Zahl groß sind. Das macht aus folgendem Grund Sinn:Ist die zu prüfende ungerade Zahl keine Primzahl, wäre sie spätestens mittels x*y bis zu ihrer Quadratwurzel gefunden worden. Hat man noch nichts gefunden, ist es eine Primzahl.

Beispiel:

Zu prüfenden Zahl: 21
Quadratwurzel aus 21: 4.58
Teiler durch Primzahlen: 21 / 1 = 21, 21 / 3 = 7 (Teiler gefunden, keine Primzahl)

Zu prüfenden Zahl: 23
Quadratwurzel aus 23: 4.8
Teiler durch Primzahlen: 23 / 1 = 23, 23 / 3 = 7.67 (Teiler nicht gefunden, Primzahl)

Noch mehr Freude herrschte, als dies meinen Kopf durchstreifte. Prompt wurde es in meinen Code implementiert. Mit Erschrecken stellte ich Fest, dass die Berechnung bis zu einer Million plötzlich auf 9 Minuten stieg. Seltsam, sollte doch jetzt noch schneller sein, weil bei 1000 Zahlen (Quadratwurzel = 31,6) nur noch gegen 11 Zahlen geprüft werden müssten. Bei einer Million (Quadratwurzel = 1000) nur noch gegen 168 anstatt 78498 Zahlen.

Nach Geschwindigkeitsmessungen der for-Schleife bis zu einer Million (for (i = 0; i < 1000000; i++)) und der Quadratwurzel von einer Million (sqrt(1000000)) hat sich herausgestellt, dass die Quadratwurzel Funktion sqrt ca. 15 Mal langsamer ist als die unnötig in die Länge gezogene for-Schleife.

Nun gilt es auch noch nach einer schnelleren Methode zu suchen eine Quadratwurzel ziehen zu können. What a pitty :-/

Goldbachsche Vermutung – 2

Posted in c0de on February 13th, 2012 by serge

Die Dusche ist eine der wichtigsten Errungenschaften der heutigen Zivilisation, zumindest was das Nachdenken angeht. Man ist mit dem mechanischen Ablauf des sich Säuberns beschäftigt, eine Tätigkeit, der man sich mehrere Jahrzehnte hingegeben hat und die einem ganz bestimmt keinen Funken geistiger Anstrengung mehr abverlangt. Man denk nicht mehr nach, ob der linke oder der rechte Arm jetzt dran ist, habe ich schon den Hals gewaschen oder sind jetzt schon die Füße dran? Man macht es einfach, ohne nachzudenken, absolut mechanisch. Der Kopf ist absolut frei, frei für wichtige Gedanken, frei für die besten Gedanken bzw. Ideen überhaupt!

So erging es mir heute ebenfalls. Plötzlich dachte ich darüber nach wieso ich eigentlich bei der Prim-Eigenschaften Berechnung immer von der zu überprüfenden Zahl abwärts laufen lasse? Also versuche die zu überprüfende Zahl mit jeder Zahl bis eins modulo zu nehmen. Das ergibt doch keinen Sinn! Bis zur Hälfte der zu überprüfenden Zahl wird das modulo Ergebnis immer ungleich null sein. Somit habe ich die vorhandene for-Schleife so abgeändert, daß sie die zu überprüfende Zahl nur noch mit den Zahlen ab der Hälfte abwärts modulo genommen werden.

for (i = ((z - (z % 2)) / 2); i > 1; i--)

Nach der Änderung der Schleife kam der Algorithmus auf das millionste Ergebnis bereits nach 42 Minuten und 18 Sekunden. Mehr als doppelt so schnell wie vorher!

Beim weiteren Sinnieren im Verlaufe des Nachmittags kam mir die Frage wie hoch denn die Wahrscheinlichkeit wäre, daß die zu überprüfende Zahl modulo einer hohen Zahl gleich null wäre gegenüber einer modulo Operation mit einer kleinen Zahl. Also zum Beispiel wie wahrscheinlich es wäre, daß 27 % 13 gleich 0 wäre gegenüber 27 % 3 gleich 0 wäre. Somit kehrte ich die Schleife einfach um. Gleichzeitig erlaubte ich der Funktion zurückzukehren, wenn die zu überprüfende Zahl eins wäre. Da jede Primzahl nur durch sich selbst und durch eins teilbar ist, kann ich die Schleife ruhig von 3 zählen lassen.

for (i = 3; i < ((z - (z % 2)) / 2); i++)

Schon schrumpfte die Rechenzeit auf unglaubliche 9 Minuten und 55 Sekunden. Quasi ein Bruchteil des ursprünglichen Wertes!

Später des Abends fragte ich mich wozu die modulo Operation mit geraden und ungeraden Zahlen durchgeführt wird. Die modulo Operation einer ungeraden Zahl mit einer geraden kann doch nie null ergeben. Somit folgte wieder eine Änderung der for-Schleife.

for (i = 3; i < ((z - (z % 2)) / 2); i += 2)

Wie man erkennen kann, zählt die Schleife immer um zwei hoch. Somit werden nur noch ungerade Zahlen berücksichtigt. Auch nach dieser Änderung sank die Rechenzeit. Dieses Mal waren es nur noch 5 Minuten und 19 Sekunden.

Nun frage ich mich nach dem Erfolg des Verringerns der Laufzeit von 106 auf 5 Minuten an einem Tag, ob ich nicht öfter am Tag oder eher den ganzen Tag lang duschen sollte. Und ob mein Notebook strömendes Wasser überhaupt verträgt und/oder ob es generell Unterwassernotebooks gibt. Würde ich eine extra Halterung für das Notebook in der Dusche benötigen? Vielleicht doch lieber Tisch und Stuhl in der Dusche installieren? Na, ich weiß ja nicht…

BTW: Bugfix in der ersten for-Schleife in der Berechnung der Summe. Die letzte Stelle im Array ist immer eins weniger als die Array Grösse selbst. Was für ein lustiger Fehler…

for (i = (arr_size - 1); i >= 0; i--)

Außerdem stelle ich grad fest, dass entweder mein Code recht seltsam ist (und daran besteht kein Zweifel) oder die Speicherverwaltung verhält sich unter Linux im Gegensatz zum OpenBSD ein wenig anders als erwartet. Segmentation fault. Wie schade.

Goldbachsche Vermutung

Posted in c0de on February 12th, 2012 by serge

Ich bin mir sicher, daß ich bei weitem nicht der erste bin, der seinen Spaß damit hat. Die Vermutung ist so simpel wie kompliziert: jede gerade Zahl ist die Summe zweier Primzahlen. Klingt recht einfach, bewaffnet mit einem Blatt Papier und einem Bleistift geht man die geraden Zahlen von vorne durch, addiert so lange zwei Primzahlen, bis man auf die ganze Zahl kommt. Für z.B. 4 wäre es 1+3, für 6 wäre es 1+5 oder 3+3 usw. Sieht wirklich recht einfach aus und wenn man Spaß an Zahlen hat, versucht man das bis zur Zahl x.

Rechnerisch wäre die Vermutung bis Zahl x bewiesen, doch wie hoch würde die bewiesene Zahl sein auf unserem Blatt Papier? Ein Tausend? Vier Tausend? Womöglich sogar zehn Tausend? Denken wir doch mal ein bißchen größer, was ist mit zwei Milliarden? Macht das unser Kopf und vor allem unsere Geduld überhaupt mit? Immerhin müßte man peu á peu eine Milliarde gerader Zahlen bewiesen haben, um sicher zu stellen, daß alle bisherigen geraden Zahlen der Goldbachschen Vermutung entsprechen. Das heißt man müßte es mathematisch lösen.

Wie wir wissen hat Mathematik recht wenig mit Rechnen zu tun. Mit Rechnen kann man keine allgemein gültigen mathematischen Beweise vollführen. Damit sind bestätigende und nicht bestätigende Beweise für alle Zahlen gemeint. Die Vermutung mathematisch nachzuweisen ist sicherlich eine Herausforderung, vor allem für mich, einen mathematisch eher unbedarften Menschen. Rechnerisch jedoch… Dafür hat man ja eigentlich Rechner, so habe ich mir gedacht.

Was müßte das Programm machen? Eigentlich ja nur alle Zahlen von null aufwärts durchlaufen, ob sie gerade bzw. ungerade sind prüfen. Bei ungeraden Zahlen auf Prim-Eigenschaften prüfen, Primzahlen in ein Prim-Array schieben, bei geraden Zahlen die Summe prüfen. Somit sah der erste Entwurf wie folgt aus:

Wie man sehen kann, geht das Programm in eine Schleife hinein, unterscheidet zwischen geraden und ungeraden Zahlen, untersucht ungerade Zahlen, berechnet gerade Zahlen und fängt wieder von vorne an.

/*
 * prim_srv.c
 */

#include <sys/errno.h>

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "prim_srv.h"
#include "errexit.c"
#include "debug.c"
#include "prim.c"
#include "summ.c"

extern int errno;

int main (int argc, char *argv[])
{
    int i = 0;
    int j = 0;

    int* prim_no;
    int* prim_no_tmp;
    int prim_no_size = 0;

    prim_no        = (int*) malloc ((prim_no_size + 1) * sizeof(int));
    prim_no_tmp    = (int*) malloc ((prim_no_size + 1) * sizeof(int));
    prim_no[0]     = 0;
    prim_no_tmp[0] = 0;

    while (1)
    {
        i++;

        if ((i % 2) == 0)
        {
            if (i > 0 && summ (i, prim_no, prim_no_size) == 0)
            {
                printf ("prim_srv - %i - keine summe vorhanden!\n", i);
                break;
            }
        }
        else
        {
            if (prim(i) == 1)
            {
                if ((prim_no_tmp = (int *) malloc ((prim_no_size + 1) * sizeof(int))) == NULL)
                    errexit ("prim_srv - error malloc of prim_no_tmp");

                for (j = 0; j < prim_no_size; j++) prim_no_tmp[j] = prim_no[j];
                prim_no_tmp[prim_no_size++] = i;

                free (prim_no);
                prim_no = NULL;

                if ((prim_no = (int*) malloc ((prim_no_size) * sizeof(int))) == NULL)
                    errexit ("prim_srv - error malloc of prim_no");

                for (j = 0; j < prim_no_size; j++) prim_no[j] = prim_no_tmp[j];

                free (prim_no_tmp);
                prim_no_tmp = NULL;
            }
        }
    }
}

Damit nicht alles in einer riesigen Datei hockt, habe ich kurzerhand die Prim-Eigenschafts- und die Summen-Berechnung in zwei extra Dateien ausgelagert, prim.c und summ.c.

/*
 * berechnet primzahlen
 *
 * z: zu untersuchende zahl
 */

int prim (int z)
{
    int i = 0;
    for (i = (z - 1); i > 1; i--)
    {
        if ((z % i) == 0)
        {
            return 0;
        }
    }
    return 1;
}

Die Untersuchung einer ungeraden Zahl auf ihre Prim-Eigenschaften gestaltet sich recht einfach: man nehme die Zahl, gehe alle Zahlen von der gegebenen Zahl abwärts bis eins und versuche die zu überprüfende ungerade Zahl mit der abwärts laufenden Zahl modulo zu nehmen. Falls der ermittelte Restwert der modulo Operation null ergibt, ist die untersuchte ungerade Zahl keine Primzahl.

Wie man unschwer erkennen kann, ist dieser Algorithmus zwar recht einfach, jedoch auch ziemlich rechenaufwändig. Da sollte man beizeiten das Mathematikbuch herausholen und tatsächlich darüber nachdenken wie man den Algorithmus intelligenter gestalten kann.

/*
 * berechnet Summe
 *
 * z:        zu untersuchende zahl
 * arr:      array mit primzahlen
 * arr_size: groesse des arrays
 */
int summ (int z, int arr[], int arr_size)
{
    int i = 0;
    int j = 0;
    int has_summ = 0;
    int i_j_summ = 0;

    for (i = arr_size; i >= 0; i--)
    {
        i_j_summ = 0;
        for (j = 0; j < arr_size; j++)
        {
            i_j_summ = arr[i] + arr[j]; 

            if (i_j_summ > z) break;
            has_summ = (i_j_summ == z) ? 1 : 0;

            if (has_summ == 1) break;
        }
        if (has_summ == 1) return has_summ;
    }
    return has_summ;
}

Bei der Untersuchung der Summe bei den geraden Zahlen habe ich mir noch weniger Mühe gegeben. Man nehme das Primzahlen Array gehe das äußere von hinten nach vorne, das innere von vorne nach hinten durch und addiere die Primzahlen der äußeren Schleife mit den Primzahlen der inneren Schleife so lange, bis man auf die gesuchte gerade Zahl kommt.

Tja, was nun? Das Programm ist klein, hübsch und läuft vor sich hin. Für 1000000 Zahlen hat mein sechs Jahre alten Notebook ganze 103 Minuten und 28 Sekunden gebraucht. In Ordnung, es hat ja nur einen Prozessor, somit teilen sich das Betriebssystem und die Berechnung die Rechenzeit. Um bis in eine tiefe Milliardenzahl vorzudringen, muß das Programm schneller werden! Es ist jedoch so schrecklich einfach konstruiert, daß da eigentlich kein Potential mehr drin steckt. Ja, bis auf die Berechnung der Prim Eigenschaften und die Berechnung der Summen. Darüber habe ich mich jedoch bereits vorher muckiert… Ach … und das Herumkopieren des dynamisch allozierten Arrays schaut beim Erweitern des Primzahlen Arrays auch recht seltsam aus. Das geht bestimmt intelligenter…

Ein neuer Ansatz muß her. Wer sagt denn, daß das Programm nur auf einer Maschine rechnen soll? Wie wäre es, wenn das Programm als Server dient und nur die Zahlen an den Client zwecks Prüfung bzw. Berechnung schickt? Oder noch besser: die Zahlen an viele Clients verteilt? Doch wie läßt sich das bewerkstelligen, ohne daß man nach jeder Anfrage an den Client ewig auf eine Antwort wartet, um anschließend die nächste Zahl prüfen bzw. berechnen zu lassen? Oder wie soll das Programm mit vielen Clients gleichzeitig umgehen? Sollte man den klassischen Client/Server Kommunikationsweg oder den RPC Weg wählen? Wie soll das Übergeben des Arrays mit Primzahlen an die Berechnung bei der klassischen Kommunikation funktionieren? Wird es überhaupt noch mit RPC gehen? Muß man die vielen Clients durch Generierung mehrerer Prozesse bedienen? Und wie sieht es mit der Rückgabe der Ergebnisse von den Prozessen an den Server? Wäre da die Interprozesskommunioation der beste Weg oder eher simples wegschreiben der Rückgabe auf die Festplatte? Und was ist mit dem Speichern der Ergebnisse in Arrays, wenn mehrere Clients die Ergebnisse im gleichen Augenblick zurück liefern? Sollte man Semaphore einsetzen, um das zu schreiben zu steuern?

Kommt Zeit, kommt Rat.

scp/sftp/rsync only jail

Posted in c0de on August 19th, 2010 by serge

a few days ago i was looking for some kind of a possibility to tell a user, that he can only copy files from a specified directory. no login, only copying files from this directory. i was looking for some kind of a jail.

i found a really nice howto for a chroot jail to lock users into their home directories. the funny thing is that the user does not know that he is in a jail. it looks like a usual unix environment. you have also the possibility to allow scp, sftp and/or rsync. 

=> cyberciti.biz

delete last 3 files

Posted in c0de on April 15th, 2010 by serge

I have a little problem. Every time I deploy a release, I move the old one into an old-folder. The problem is: is there a way to delete all files in this old-folder except the 3 last files? kind of an opposite of ls -tr | tail -n 3?

I took half an hour and hacked a little script the easy and st00pid way:


#!/bin/bash
#
# Name: del-except-3
# Author: pes
# Date: 08.04.2010
# Description
# Deletes all files in ${searchpath} except the last 3
#

debug=1
searchpath=$1

if [ ! -d ${searchpath} ]; then
    echo "${searchpath} does not exist"
    exit 1
fi

cd ${searchpath}

last3=`ls -tr | tail -3`

set -- ${last3}

last3_1=$1
last3_2=$2
last3_3=$3

if [ ${debug} -ne 0 ]; then
    echo "last 3 files in ${searchpath}"
    echo " 1: $last3_1"
    echo " 2: $last3_2"
    echo " 3: $last3_3"
fi

for i in `ls -1`; do
    if [ "${i}" != "${last3_1}" ]; then
        if [ "${i}" != "${last3_2}" ]; then
            if [ "${i}" != "${last3_3}" ]; then
                echo "rm ${searchpath}/${i}"
                rm ${i}
            fi
        fi
    fi
done

is there a smart combination of shell commands? someting that does not look that stupid?

impressum