ubuntuusers.de

Funktion soll array zurückgeben

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

oliver1804

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

Hallo liebe Gemeinde,

das folgende kleine AWK-Skript soll

a) per Funktion die Dateien eines Verzeichnisses in ein Array lesen

b) die Dateien ausgeben

Ich bekomme leider immer wieder diese Fehlermeldung

"gawk: test.awk:22: Fatal: Versuch, das Array 'files_arr' in Skalarkontext zu verwenden."

Was mache ich verkehrt?

BEGIN {
verzeichnis_arr("c:\\", "*.*")

for(i in files_arr) {
	print files_arr[i]
}

}

function verzeichnis_arr(vz, dat,   ord_fil_abfrage, i, files_arr) {
# Rückgabe der Dateien im Vz als Array

ord_fil_abfrage = "dir /B " vz dat
	
	i=0
		
	while((ord_fil_abfrage | getline files)>0) {
		i++
		files_arr[i] = files
	}
		return files_arr
}

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

Offenbar ist die Rückgabe eines Arrays gar nicht möglich, so daß am besten ein (uninitialisiertes) array als Funktionsargument übergeben werden sollte, welches dann entsprechend befüllt und auch außerhalb der befüllenden Funktion ausgegeben werden kann

Irgendwelche Tipps, wie man das besser bewerkstelligen kann?

BEGIN {

verzeichnis_arr(files_arr, "c:\\", "*.*")

for(i in files_arr) {
	print files_arr[i]
}

}

function verzeichnis_arr(arr,vz, dat,   ord_fil_abfrage, i) {
# Rückgabe der Dateien im Vz als Array

ord_fil_abfrage = "dir /B " vz dat
	
	i=0
		
	while((ord_fil_abfrage | getline files)>0) {
		i++
		files_arr[i] = files
	}
}

Skeeve

Avatar von Skeeve

Anmeldungsdatum:
12. Juli 2007

Beiträge: 24

oliver1804 hat geschrieben:

Irgendwelche Tipps, wie man das besser bewerkstelligen kann?

Perl verwenden? 😉 Ich, als Neuling, will niemanden verärgern, aber ich verwende seit ca. 12 Jahren immer Perl anstelle von sh/sed/awk. Es läuft halt "alles in einem".

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

okay,

wie schaut denn diese Sache in Perl aus (werd ich zwar fürs jetzige Projekt nicht anwenden, aber hilft mir vielleicht für die Zukunft)

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

In Python sähe es so aus:

from glob import glob

dateinamen = glob(r'c:\\*.*')

for dateiname in dateinamen:
    print dateiname

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

@Marc 'BlackJack' Rintsch

Sieht angenehm kurz aus verglichen mit dem was ich da so geliefert hab;

wozu dient

"from glob import glob" ?

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

oliver1804 hat geschrieben:

wozu dient
"from glob import glob" ?

Ich denke mal damit importiert er den glob befehl aus dem "package?" glob in seinen Namespace.

okay,
wie schaut denn diese Sache in Perl aus (werd ich zwar fürs jetzige Projekt nicht anwenden, aber hilft mir vielleicht für die Zukunft)

Marcs Code in Perl könnte man so schreiben:

print map { "$_\n" } glob "c:\\*.*"


oder so:

print "$_\n" for glob 'c:\\*.*'

Ich schreibe hier explizit Marc Code, weil Marc und mein Code nicht genau das machen, was du wolltest.

Ansonsten hängt es eher von dem ab was du machen möchtest. Eine Subroutine zu bauen die dir die Dateinamen aus einem Verzeichnis zurück gibt halte ich für ziemlich Sinnfrei, weil es ja genau das ist was "glob" z.B. macht. Zum anderen stellt sich die frage sich was du genau mit der Liste machen möchtest. Testen auf einem Dateiende, testen ob lesbar. Vielleicht möchtest du rekursiv Dateien durchgehen etc. Je nach Anforderung kann man da bessere Sachen nutzen.

\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\––\–––-

In der Fehlermeldung zu deinem awk Skript steht das ein Array im Skalarkontext verwendet wird. Wenn diese Fehlermeldung kommt, dann sieht es für mich aber auch so aus, als das es einen Listenkontext geben würde. Und wenn ich es richtig sehe, dann heist deine Funktion doch "verzeichnis_arr" ?

Und ganz oben im Skript rufst du die Funktion so auf. "verzeichnis_arr("c:\\", "*.*")" Nun welchen Sinn macht es eine Funktion aufzurufen die ein Array zurück gibt, wenn du das zurückgegebene Array nirgendswo Speicherst?

Von daher macht diese Fehlermeldung schon Sinn...

Aber kann kein awk. Für mich sieht das aber so schon falsch aus. Ich denke mal in awk sind alle Variablen Global? Wenn nicht würde dein Code noch weniger Sinn ergeben, da in deiner for Schleife "files_arr" vor seiner Verwendung nirgendso "gefüllt" wird. Logisch wäre für mich dann z.B. soetwas:

files_arr = verzeichnis_arr("c:\\", "*.*")

files_arr wird allerdiengs in deiner Funktion gefüllt. Sind Variablen automatisch Global dann macht der Code Sinn. Allerdiengs muss deine Funktion dann nichts mehr zurück geben (return).

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

@ Sid Burn

files_arr = verzeichnis_arr("c:\\", "*.*")

etwas in der Art hatte ich bereits - auch wenn ich es nicht geschrieben habe - ohne Erfolg versucht (ein Array kann wohl auf diese Art nicht zurückgegeben werden)

gawk -f test.awk

–- test.awk –-

BEGIN {
print a
print "hallo"
}


function test() {
a = 3
} 

liefert eine Leerzeile (für die uninitialisierte Variable a und eine Zeile mit hallo, so daß ich mal davon ausgehe, daß Variablen nicht automatisch global sind.

Was ich möchte:

im Rahmen eines "kleinen" Skriptes kopiere ich bestimmte dbase-Dateien aus einem Arbeitssystem (vom Betriebsserver) herunter, um sie lokal weiterzuverarbeiten. Ich lese diese Dateien dann aus dem lokalen Verzeichnis in ein Array, um dann per externem Hilfsprogramm je nach Dateityp unterschiedliche SELECT-Aufrufe drüberlaufen zu lassen - das Ergebnis wird dann wieder in Textdateien gespeichert, damit ich dann im nächsten Schritt einige dieser Dateien nach Bedarf umstrukturieren kann, wobei es sich wieder nur um ein Zwischenergebnis handelt - im Endergebnis sollen die Dateien mehrerer/eines Tageslieferscheine(s) in einer Einzeldatei an eine Tourenoptimierung übergeben werden, wobei in der Vorgehensweise bei der Erstellung der Übergabedatei ein Unterschied zwischen den Tageslieferscheinen vom Sonntag und denen von Montag bis Samstag zu machen ist (nur so allgemein). Ein erstes Ergebnis (aktueller Stand ist im Büro) findest du hier http://www.ubuntuusers.de/paste/12502/

Bin noch sehr stark am Lernen was Skripting angeht, aber ich habe die Hoffnung, das Problem mit ein wenig Übung in den Griff zu bekommen. Letztlich komm ich aufgrund der Komplexität und der Häufigkeit, mit der derartige Daten zu erstellen sein werden, nicht um eine "programmatische" Lösung herum. Bin nicht der Programmierguru und beabsichtige auch nicht, einer zu werden. Ziel ist nur, mir ein wenig selber helfen zu können (sh. dazu auch folgende Noob-Frage: http://forum.ubuntuusers.de/topic/102721/?highlight=).

AWK ist für mich das Mittel der Wahl, da ich vor einiger Zeit mal angefangen hab, damit Probleme zu lösen, die über die Möglichkeiten von gvim und sed hinausgingen und diese Skriptsprache bei derartigen Problemen immer mal wieder verwendet habe. Es ging bei diesen Problemen aber immer nur um Datensätze mit fester Satzlänge, die dann eben auf Richtigkeit geprüft werden mußten, bevor ich dann je nach Problemstellung in MySQL/ACCESS oder auch EXCEL eingelesen hab. Da ich den Eindruck hab, daß ich die Möglichkeiten von awk bisher noch nicht wirklich erkannt geschweige denn genutzt habe, bin ich diesen Weg eben weiter gegangen.

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

liefert eine Leerzeile (für die uninitialisierte Variable a und eine Zeile mit hallo, so daß ich mal davon ausgehe, daß Variablen nicht automatisch global sind.

Öhm, naja in deinem Beispiel hast du zwar eine Subroutine test() definiert die die Variable a setzt. Da du die Funktion aber nie aufrufst wird sie auch logischerweise nicht gesetzt. Wenn du dein Beispiel so abänderst:

BEGIN {
    test()
    print a
    print "hallo"
}


function test() {
    a = 3
}

Dann wird auch eine 3 ausgegeben. Sieht also sehr stark nach Globalen Variablen aus...

Von daher kannst du das return in deinem Code ohnehin weg lassen. Naja gerade saubere Programmierung ist das nicht...

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

Herrgott ..

ähh, darf ich Sid sagen 😉

EDIT:
und ich De.. hab mich schon gefragt, wieso die Doku

"The arguments and local variables last only as long as the function body is executing.
Once the body finishes, you can once again access the variables that were shadowed while
the function was running."

sowas enthält, wenn es doch gar nicht stimmt

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

Was stimmt denn daran nicht? a ist keine lokale Variable!

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

@ Marc 'BlackJack' Rintsch

eben, bevor mich Sid drauf aufmerksam gemacht hat, daß ich die Funktion test() nicht aufgerufen hab, hab ich da einen Widerspruch zwischen meinem Ergebnis und der Doku gesehen

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

oliver1804 hat geschrieben:

ähh, darf ich Sid sagen 😉

Klar.

\––\––\––

Ansonsten habe ich mal etwas über awk gelesen. Alle Variablen sind automatisch Globale Variablen. Lokale Variablen kannst du nicht direkt erstellen. Alle Variablen die du aber bei deiner Funktion zusätzlich angibst sind lokal.

function test(arr)

Hier würde z.B. die Variable "arr" lokal sein. Wenn du also zusätzliche lokale Variablen haben möchtest, musst du diese als Funktionsparameter angeben. Eine Funktion kannst du ja ohne Probleme mit weniger Argumenten aufrufen. Alle weiteren werden automatisch mit einem Null String angelegt.

Ansonsten hatte ich soetwas mal Probiert.

BEGIN {
    blub = test()

    for ( i in blub ) {
        print blub[i]
    }
}

function test(arr) {
    arr[0] = "Hallo"
    arr[1] = ", Welt!"
    return arr
}

Allerdiengs geh es nicht. Er meckert dann das man keine Referenz auf eine lokale Variable zurück geben kann. Da Allerdiengs Array mit "Call by Reference" übergeben werden, könntest du folgendes machen.

BEGIN {
    test( blub )

    for ( i in blub ) {
        print blub[i]
    }
}

function test(arr) {
    arr[0] = "Hallo"
    arr[1] = ", Welt!"
}

Das ist etwas sauberer und C Typisch. Sprich du gibst als Functionsparamter sozusagen ein Pointer auf das Array, und in deiner Funktion bearbeitest du direkt das Array.

Unsauberer geht dann natürlich auch soetwas:

BEGIN {
    test()

    for ( i in arr ) {
        print arr[i]
    }
}

function test() {
    arr[0] = "Hallo"
    arr[1] = ", Welt!"
}

Allerdiengs halte ich soetwas für schwer Wartbar, vorallem wenn dein programm etwas größer wird. Ansonsten geht es mir schon auf die Nerven das "print" automatisch ein Newline am ende erzeugt. Total bescheuert. Naja ich Programmiere ja nicht in awk. 😉

oliver1804

(Themenstarter)

Anmeldungsdatum:
27. März 2006

Beiträge: 279

Wohnort: Elmshorn

eine Unterscheidung zwischen globalen und privaten Variablen kann offenbar nur durch ein System bei der Benamsung erfolgen, so daß man seine lokalen Variablen bspw. mit einem großen Anfangsbuchstaben und im Programmteil dann nur mit Kleinbuchstaben beginnt

http://www.gnu.org/software/gawk/manual/html_node/Library-Names.html#Library-Names

die lexikalischen Variablen in Perl scheinen mir verglichen hiermit eine tolle Sache zu sein, da ich dadurch eine Zählervariable wie i immer wieder bedenkenlos verwenden kann ohne diese jedesmal wieder auf 0 setzen zu müssen

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

Naja, das i würde man in AWK lokal zur Funktion deklarieren und schon stört's nicht mehr. Oder hast Du öfter Zähler mit so generischen Namen auf Modul/Paket/Bibliotheksebene? Das erscheint mir zumindest merkwürdig.

Antworten |