ldapsearch-Abfrage für CSV-Liste zuverlässig sortieren lassen?

Hallo.
Nach längere Pause melde ich mich mal wieder mit einer Frage:

Ich frage das Active Directory des lmn7-Servers per ldapsearch mit Parametern wie diesen ab, um eine Liste von Schülern mit den Feldern
Vorname; Nachname; Login; Klasse;
zu bekommen:

ldapsearch  -b $base -H $server -x -D $binduser -w $bindpw 

'(&(!(sophomorixAdminClass=attic))(|(sophomorixRole=student)))' 

| grep  -e sophomorixFirstnameASCII: 
        -e sophomorixSurnameASCII: 
        -e sAMAccountName: 
        -e sophomorixAdminClass:  

| awk '{printf $2";"}  NR%4==0 {printf"\n"}' 

| sort -n 

Das funktioniert auch – aber leider ist die Sortierung/Ausgabe nicht zu 100% zuverlässig.

Bei den meisten Usern bekomme ich diese Reihenfolge

sAMAccountName:;sophomorixFirstnameASCII:;sophomorixSurnameASCII:;sophomorixAdminClass:;

aber bei einigen anderen sieht das leider so aus:

sAMAccountName:;sophomorixAdminClass:;sophomorixFirstnameASCII:;sophomorixSurnameASCII:;

Ich weiß nicht, woran das liegt. Diese User sind alle erst später dazu gekommen, denn sie befinden sich durchgängig in Klasse 5 – also alle neu hinzugekommen im letzten Jahr und nicht durch die Migration von v6 → v7 ins System gelangt!

Ich benötige natürlich immer das gleiche Ausgabeformat, damit die Weiterverarbeitung der CSV-Datei zuverlässig funktioniert.

Der awk-Befehl sortiert die Ausgabe von ldapsearch so um, dass alles in einer Zeile erfolgt, doch innerhalb dieser Zeile müsste das offenbar nochmal zuverlässig nach den o.g. Kriterien sortiert werden??

Hat jemand eine gute Idee, wie man das hinkriegen kann?

Danke.
Viele Grüße,
Michael

Hallo Michael,

ich hab das grad mal bei mir probiert und dabei gemerkt, dass die Reihenfolge der LDAP-Felder bei der Abfrage zwar immer sehr ähnlich aber halt doch nicht ganz gleich ist.
Ich sehe bei mir auch Schüler aus den 6. Klassen, bei denen das „falschrum“ sortiert ist.
Da man sich auf die Sortierung nicht verlassen kann, denke ich, dass kein Weg daran vorbei führt, die komplette Ausgabe abzuwarten und dann selbst zu sortieren. Ganz spontan fehlt mir aber die Idee, wie man das

  • ähnlich elegeant wie deine Pipe-Kette in einen Einzeiler bringen kann
  • ohne ldap-Mehrfachabfragen sicher in einen Mehrzeiler implementieren kann

Aber - wusstest du vermutlich schon - schuld ist schon die Antwort des LDAP-Servers

LG Jesko

Hallo Michael,
zweiter Versuch mit etwas besserer Formatierung…

Blöd, wenn man sich nicht auf die Korrekturen konzentrieren kann, weil man auf so eine Knobelei getriggert wurde…
… was du vermutlich suchst ist das hier:

ldapsearch  -b $base -H $server -x -D $binduser -w $bindpw 

'(&(!(sophomorixAdminClass=attic))(|(sophomorixRole=student)))' 

| awk -v OFS=',' '{split($0,a,": ")} /^sAMAccountName:/{login=a[2]} /^sophomorixAdminClass:/{klasse=a[2]} /^sophomorixFirstnameASCII:/{vorname=a[2]} /^sophomorixSurnameASCII/{nachname=a[2]; print klasse";"nachname";"vorname";"login}'

| sort -n 

LG Jesko

Hallo Jesko … Korrekturen? Unwichtig :slight_smile:
Vielen Dank für’s Mitdenken bzw auch dafür, dass Du Dich von dem Problem antriggern ließest!
Die Syntax funktioniert einwandfrei! Ich habe den Filter noch etwas erweitert und kann das jetzt auch pro Klasse einsetzen. Super! Besten Dank!

Hallo Michael!

Würdest du den auch posten, bitte?

Beste Grüße

Thorsten

Hallo Thorsten,
so habe ich das erweitert:

'(&(!(sophomorixAdminClass=attic))(|(sophomorixRole=student))(|(sophomorixAdminClass='$j'*)))'

Das $j ist die Variable für die Jahrgänge oder für die Klassen…
hth,
Michael

Hallo Michael,

nur am Rande: Die beiden Oder-Operatoren wirken bei Deinem Ausdruck nur auf je ein Argument, da kann man sie auch weglassen:

'(&(!(sophomorixAdminClass=attic))(sophomorixRole=student)(sophomorixAdminClass='$j'*))'

Beste Grüße

Jörg

Hallo @Jesko!
Ich habe das Script heute nochmal ausprobiert und dabei bemerkt, dass es einen Fehler gibt.

Hier nochmal ein Beispiel:

ldapsearch  -b "ou=default-school,ou=SCHOOLS,dc=linuxmuster,dc=lan" -H ldaps://server.linuxmuster.lan:636 -x -D global-binduser@linuxmuster.lan -w geheimespasswort  '(sophomorixAdminClass=8a)' | awk -v OFS=';' '{split($0,a,": ")} /^sAMAccountName:/{login=a[2]} /^sophomorixAdminClass:/{klasse=a[2]} /^sophomorixFirstnameASCII:/{vorname=a[2]} /^sophomorixSurnameASCII/{nachname=a[2]; print vorname";"nachname";"login";"klasse";"}'

Das spuckt alle User der 8a in der angegebenen Reihenfolge aus – leider macht es hier aber einen Fehler: Beim ersten User fehlt die letzte Spalte.

Dort steht also in der letzten Spalte keine Klasse, während es in allen anderen Zeilen funktioniert. Nach etlichen Tests habe ich gesehen, dass das Problem (zufällig) immer genau dann auftaucht, wenn beim ersten (aber nur beim ersten!) Login einer Klasse der Eintrag sophomorixAdminClass erst nach den Einträgen sophomorixFirstnameASCII und sophomorixSurnameASCII ausgespuckt wird. Die Frage ist, warum das ein Problem ist?

Danke nochmal und viele Grüße,
Michael

Hier nochmal ein Minimalbeispiel:

cat testfile.txt

# extended LDIF
#
# LDAPv3
# filter: (sophomorixAdminClass=1)
# requesting: ALL
#

sAMAccountName: testuser1
sophomorixFirstnameASCII: Max
sophomorixSurnameASCII: Mustermann
sophomorixAdminClass: 1

sAMAccountName: testuser2
sophomorixAdminClass: 2
sophomorixFirstnameASCII: Testx
sophomorixSurnameASCII: Testman-x

sAMAccountName: testuser3
sophomorixFirstnameASCII: Testy
sophomorixSurnameASCII: Testwoman-y
sophomorixAdminClass: 3

und siehe da:

cat testfile.txt | awk -v OFS=',' '{split($0,a,": ")} /^sAMAccountName:/{login=a[2]} /^sophomorixAdminClass:/{klasse=a[2]} /^sophomorixFirstnameASCII:/{vorname=a[2]} /^sophomorixSurnameASCII/{nachname=a[2]; print login","vorname","nachname","klasse","}' 

sortiert es falsch – ändert man aber die Reihenfolge für den ersten Eintrag, so dass der Eintrag sophomorixAdminClass nicht ganz hinten steht, klappt es … es scheint also auch weiterhin problematisch zu sein, dass die Reihenfolge der Felder nicht immer gleich erfolgt. Nur: Wie kann man das ändern?
Das sollte für awk doch eigentlich kein Problem sein :thinking: :interrobang:

Neuer Versuch … so sieht’s besser aus (Danke an d.c.o.u.s):

| awk '$NF == 0 {if (login vorname nachname klasse != "")  print login","vorname","nachname","klasse","; login = vorname = nachnam
e = klasse = "" } /^sAMAccountName: / { login = $2 }   /^sophomorixAdminClass: / { klasse = $2 } /^sophomorixFirstnameASCII: / {vorname = $2 } /
^sophomorixSurnameASCII: / { nachname = $2}' |sort -t"," -k4 -k2

Hallo.
Ich pushe das Thema nochmal nach oben, weil das ldapsearch- und awk-Geraffel zu nerven beginnt und immer wieder Fälle auftauchen, bei denen die Syntax nicht zuverlässig greift. Meistens fehlen dann Einträge, was man aber erst viel später merkt…

Daher nochmal die Frage an die @Entwickler:
Gibt es einen kürzeren und eleganteren Weg als den hier gezeigten, wie man zuverlässig und sauber eine Liste erhält, in der diese Felder vorkommen:
sAMAccountName
sophomorixAdminClass
sophomorixUnid
sophomorixFirstnameASCII
sophomorixSurnameASCII (oder auch anders sortiert)

Ich benötige sehr häufig Listen der Form
musmax;Max;Mustermann;1400096;8b;
meylie;Lieschen;Meyer;1110001;5a;
usw. damit ich den Namen die richtigen Logins zuordnen kann.

Das Problem taucht immer dann auf, sobald irgendwelche
Schulverwaltungsprogramme mit im Spiel sind, die den v7-Login natürlich nicht kennen. Daher läuft die Zuordnung vom Namen zum Login über die UID.

Vielen Dank und viele Grüße,
Michael

Hallo Michael,

Sind die Daten von sophomorix-print nicht geeignet? Zu finden unter /var/lib/sophomorix/print-data ?

Grüße
Sven

Könnte gehen – seit wann steht da die UID mit drin? Das war nicht immer so, oder? Feld 1 ist der gesamte Name, das müsste nochmal anders formatiert werden. Und das Erstpasswort fliegt auch raus … aber ansonsten sieht’s brauchbar aus! Danke für den Tipp. Das war echt Betriebsblindheit!

Jetzt weiß ich wieder, warum ich nicht sofort diese Datei genommen habe: Man bekommt mit sophomorix-print zwar alle Einträge in einer Datei – aber das sind zu viele (auch Extrastudents usw sind dabei). Und das Erzeugen mit der Option --class erzeugt dann wieder zig Einzelfiles … daher bin ich ursprünglich auf die ldapsearch-Variante ausgewichen, um eine einzige Datei zu haben, in der ausschließlich aktive Schüler sind.

Ok, jetzt aber … ich habe die print-data-Datei nochmal weiter verarbeiten lassen. Jetzt ist es nur noch ein Einzeiler:

sophomorix-print   
cat /var/lib/sophomorix/print-data/add-unknown-unix.csv | sed -e "s/ /;/g" | awk -F";" '{print $4";"$1";"$2";"$6";"$3";"}' | awk -F";" '$4~/^[0-9]+$/ && $5 != "attic"'

Zur Erklärung:

  • Der sed-Befehl ersetzt das Leerzeichen gegen ein Semikolon
  • der erste awk-Befehl sortiert die Spalten um
  • der zweite awk-Befehl schnappt sich nur die Einträge, die als ID eine Ziffer haben (also auch keine Lehrer!) und die sich zudem nicht im attic befinden.

Danke für den Tipp …

1 „Gefällt mir“