Nach vielen IBM-Jahren, in denen ich Erfahrungen sammeln durfte, bin ich wahrlich nicht so schnell zu überzeugen. Meine letzte große Enttäuschung war das Modernisierungs-Tool „Merlin“, das nach drei Jahren vom Vertrieb zurückgezogen wurde. Obwohl alles soweit funktionierte, waren letztendlich doch die Installationsanforderungen zu hoch. Dadurch habe ich jedoch viel Neues kennengelernt: VS Code, Code for i und den Better Object Builder, der nun nicht mehr Bob, sondern TOBi heißt – „The Object Builder for i“ –, ein Open-Source-Build-Tool für die IBM-i-Plattform.
„Bob“ ist nun der Name für IBMs KI-Plattform für die Softwareentwicklung und, wenn man so will, das Nachfolgeprojekt des „Code Assistant for RPG“. Allerdings ist sie nicht nur auf RPG beschränkt und soll auch in der IBM-i-Welt viel Gutes bewirken. Vorträge, Videos etc. gibt es dazu bereits reichlich. Heute ergab sich ungewollt die Möglichkeit eines Praxistests, der zwar nicht repräsentativ ist, mich aber dennoch in Erstaunen versetzte, denn damit hatte ich nicht gerechnet.
Seit Tagen beschäftigte mich eine Lösung, die sich ein IBM-i-Anwender wünschte. Sein Problem war, dass durch Fehler massenhaft Joblogs auf IBM i erzeugt wurden, die für ihn keinen Wert besaßen und gelöscht werden sollten. „CLROUTQ OUTQ(QEZJOBLOG)“ kennt wohl jeder IBM-i-Administrator, weiß aber auch, dass man damit eher mit einer Axt als mit einem Skalpell arbeitet.
Da ich mich derzeit viel mit Bash-Programmierung unter IBM i beschäftige, versuchte ich es auf diesem Weg. Im Prinzip ist der Algorithmus relativ einfach, da man sich über den IBM-i-Service „QSYS2.OUTPUT_QUEUE_ENTRIES_BASIC” Listen von Joblogs erzeugen lassen kann. Mit Hilfe des Open-Source-Tools „db2util“ ist dies auch als CSV-Datei möglich. Hier ein Beispiel:
db2util -o csv "SELECT SPOOLED_FILE_NAME, JOB_NAME
FROM QSYS2.OUTPUT_QUEUE_ENTRIES_BASIC
WHERE ((OUTPUT_QUEUE_NAME='QEZJOBLOG') AND
(CREATE_TIMESTAMP > '2025-12-08 10:00:00.000000') AND
(CREATE_TIMESTAMP < '2025-12-10 18:00:00.000000'))" > Liste.txt
Danach wird die Datei „Liste.txt“ Zeile für Zeile mit „DLTSPLF“ abgearbeitet. So der Plan!
Do-while-Schleifen eignen sich für so etwas wunderbar, da man schließlich nicht weiß, wie viele Einträge man zurückbekommt – dachte ich – und ging ans Werk. Da die Anzahl meiner Joblogs begrenzt war, fügte ich für Tests noch ein „fetch first 5 rows only“ hinzu. Somit hatte jede generierte Liste fünf Einträge.
Versuchen wir es zunächst mit Trockenübungen: Wir lesen die Datei „Liste.txt“ zeilenweise ein, extrahieren die gewünschten Parameter und lassen uns das Ergebnis mit „echo” ausgeben:
while read -r zeile; do
# Filtern der Zeile nach Spoolfilename
SPLFNAME=$(echo $zeile | cut -f1 -d, | sed 's/"//g')
# Filtern der Zeile nach dem Jobnamen
JOBNAME=$(echo $zeile |cut -f2 -d, | sed 's/"//g')
echo "dltsplf file($SPLFNAME) JOB($JOBNAME) SPLNBR(*any) SELECT(*ALL)"
done < Liste.txt
Ergebnis mit meiner der erzeugten 5-zeiligen Liste:
dltsplf file(QPJOBLOG) JOB(459159/QSECOFR/QS9UAK) SPLNBR(*any) SELECT(*ALL)
dltsplf file(QPJOBLOG) JOB(459634/QUSER/QRWTSRVR) SPLNBR(*any) SELECT(*ALL)
dltsplf file(QPJOBLOG) JOB(459635/QUSER/QRWTSRVR) SPLNBR(*any) SELECT(*ALL)
dltsplf file(QPJOBLOG) JOB(459635/QUSER/QRWTSRVR) SPLNBR(*any) SELECT(*ALL)
dltsplf file(QPJOBLOG) JOB(460250/QUSER/QRWTSRVR) SPLNBR(*any) SELECT(*ALL)
Super!
Nun ersetzten wir „echo” durch den Befehl „cl“, der CL-Befehle ausführt, und schauen hoffnungsvoll, was das Skript nun macht. (Zum besseren Verständnis habe ich die „echo”-Ausgabe nicht entfernt und eine zusätzliche Zeile hinzugefügt.)
dltsplf file(QPJOBLOG) JOB(459159/QSECOFR/QS9UAK) SPLNBR(*any) SELECT(*ALL)
CPD000D: Command *LIBL/DLTSPLF not safe for a multithreaded job.
Warum führt er das CL-Kommando nur einmal aus? Die Frage ist gleichbedeutend mit: „Warum wird die Schleife nur einmal durchlaufen, obwohl ich fünf Zeilen in meiner Liste habe?“
Dokumentation gewälzt und es mit einem For-Loop versucht. Da funktionierte alles, was die Fragezeichen in meinem Kopf noch weiter anwachsen ließ. Auch die Diskussion mit einem gestandenen Unix-Programmierer brachte keine neuen Erkenntnisse.
Heute Morgen stellte ich es dann einem jungen Mitarbeiter der TD Synnex, Sejid Canoski, vor, der vor Kurzem Zugriff auf die Preview von Project Bob erhielt, und er meinte: „Fragen wir doch Bob!“
Was hatten wir zu verlieren? Nichts! Schauen wir also mal, ob er dieses sehr spezielle Problem lösen kann.
Die erste Herausforderung bestand dann darin, mein Problem so zu formulieren, dass das Tool es auch verstand. Bob fragte zunächst, ob es die Datei mit dem Quellcode auch benutzen dürfe. Vorbildlicher Datenschutz! Ein Sternchen für Bob. Aber die Skepsis blieb.
Hier nochmal der Code:
Quelle: CanoskiÜberrascht hatte mich Skeptiker dann die schnelle, und vor allem hilfreiche Antwort:
Quelle: CanoskiHalluziniert Bob, oder „Isses wahr?“ – „cl“ in PASE liest also, wie die Do-while-Schleife, ebenfalls von Standard-In. (Wo steht das eigentlich in der Dokumentation?)
Ausprobiert, und es lief wie ursprünglich angedacht.
Das Hinzufügen von „</dev/null“ als „leerem“ Input-Stream, was dem Senden von „End-of-File“ an den „cl“-Befehl entspricht, war die Lösung. Hier nun der neue Code:
Quelle: CanoskiUnd das Ergebnis nach Ausführung:
Quelle: CanoskiDie Schleife wurde jetzt fünf Mal durchlaufen und damit das ursprüngliche Problem gelöst.
Bob schlug sogar eine alternative Lösung vor, die ebenfalls funktioniert, aber Kenntnisse über Deskriptoren erfordert. Ohne näher darauf einzugehen, hier Bobs Vorschlag:
while read -r zeile <&3; do
SPLFNAME=$(echo $zeile | cut -f1 -d, | sed 's/"//g')
JOBNAME=$(echo $zeile | cut -f2 -d, | sed 's/"//g')
echo "dltsplf file($SPLFNAME) JOB($JOBNAME) SPLNBR(*any) SELECT(*ALL)"
cl "dltsplf file($SPLFNAME) JOB($JOBNAME) SPLNBR(*ANY) SELECT(*ALL)"
done 3< Liste.txt
Okay, da tauchte vorhin eine neue Meldung von „DLTSPLF“ auf. Mit dem Fehlercode CPF3340 muss ich mich noch beschäftigen, aber das mache ich morgen – vielleicht auch wieder mit Bob.
Fortsetzung folgt! (Teil 2 ist bereits erstellt und wird demnächst veröffentlicht)
Ein Beitrag von Sejid Canoski, TD Synnex und Dr. Wolfgang Rother, IBM.
