Hallo zusammen, ich bastele gerade an einem kleinen Skript und habe eine Frage zu dynamischen Variablen. Vorweg die Ausgangslage. Ich habe eine LIste als Textfile vorliegen im Format name-1 hans name-2 theo produkt-1 auto attribut-3 schoen ... Jede Zeile kann also unterschiedlich beginnen und das File kann quasi beliebig lang sein. Ich möchte in einem Bash Skript nun dieses File so einlesen, dass die Variablennamen sich an Spalte eins aus dem Textfile orientieren. Um bei diesem Beispiel zu bleiben sähen die Variablen also wie folgt aus: name-1="hans" name-2="theo" produkt-1="auto" attribut-3="schoen" Ferner möchte ich darüber dann ein case statement laufen lassen der Form: case $INHALT in $name-1|$name-2|$produkt-1|$attribut-3) ... Hat jemand eine Idee wie man das elegant in Bash lösen kann? Danke und Grüße Stefan -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Fri, 26 Nov 2010, C.M. Burns schrieb:
Hat jemand eine Idee wie man das elegant in Bash lösen kann?
Gar nicht. Das was geht wäre eine gefährliche Krücke. Nimm awk, perl, python oder so. -dnh -- If you think, you're wrong, you might be right! -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
David Haller schrieb:
Hallo,
Am Fri, 26 Nov 2010, C.M. Burns schrieb:
Hat jemand eine Idee wie man das elegant in Bash lösen kann?
Gar nicht. Das was geht wäre eine gefährliche Krücke.
Nimm awk, perl, python oder so.
-dnh
Hm ich habe es schon befürchtet. Leider ist das eine extrem spartanische Installation, muss erstmal sehen ob dort awk usw überhaupt verfügbar ist. Zudem habe ich von awk und perl nur rudimentäre Kenntnisse, von python gar keine :D Hättest Du einen Lösungsvorschlag? Wie sähe denn die gefährliche Krücke aus? Danke und Grüße Stefan -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, Am Sat, 27 Nov 2010, C.M. Burns schrieb:
David Haller schrieb:
Am Fri, 26 Nov 2010, C.M. Burns schrieb: Hm ich habe es schon befürchtet. Leider ist das eine extrem spartanische Installation, muss erstmal sehen ob dort awk usw überhaupt verfügbar ist. Zudem habe ich von awk und perl nur rudimentäre Kenntnisse, von python gar keine :D
Hättest Du einen Lösungsvorschlag?
In awk und perl würde ich schlicht einen hash (aka assioziatives Array) verwenden. Ohne konkretere Anforderungen kann man dazu aber nix sagen.
Wie sähe denn die gefährliche Krücke aus?
Vergiss es einfach. Wenn man die Krücke verwenden wollte, dann muß man sich damit _SEHR_ gut auskennen. Da du fragst, tust du das offensichtlich nicht. Ergo: Von mir bekommst du keine weiteren Details. Tut mir leid, ist aber so. Und ich möchte alle anderen hier in der Liste darum bitten, sich dem anzuschliessen. Nein, das ist kein "Geheimwissen" oder sonstwas, das ist alles gut dokumentiert, das Problem ist einfach, daß man sich bei der "naiven" Anwendung so dermaßen ein Problem an den Hals hängt ... Das Problem will man keinem, der danach fragen muß aufbürden ... Und BTW: das hier ist meine letzte Mail an dich mit dem "Realnamen". Ab sofort wird Mail von C. Montgomery Burns hier nach /dev/null umgeleitet. Sei froh, daß du bis jetzt überhaupt ne Antwort bekommen hast. Auf Nimmerwiederlesen, -dnh -- FAQs are like flatulence. Any asshole can produce them. -- Toni Lassila -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo, ein typisches Problem für einen Hash bzw. assoziatives Array, in Perl sieht das in etwa so aus: #!/usr/bin/perl %hash = (); while (<>) { chop; @line = split(/\s+/, $_); $hash{$line[0]} = $line[1]; } foreach $key (sort keys %hash) { print "$key:$hash{$key}\n"; } Wenn Du das nach test.pl schreibst und Deine Daten in data.txt, dann wie folgt aufrufen: perl test.pl data.txt in die foreach-Schleife müsste dann das einfließen was Du mit den Daten anstellen willst, im Moment gibt Perl die Daten nur wieder auf STDOUT aus!! Sehr ähnlich geht das auch mit awk! Grüße Mike Am Freitag, 26. November 2010 17:20:21 schrieb C.M. Burns:
Hallo zusammen,
ich bastele gerade an einem kleinen Skript und habe eine Frage zu dynamischen Variablen.
Vorweg die Ausgangslage. Ich habe eine LIste als Textfile vorliegen im Format
name-1 hans name-2 theo produkt-1 auto attribut-3 schoen ...
Jede Zeile kann also unterschiedlich beginnen und das File kann quasi beliebig lang sein.
Ich möchte in einem Bash Skript nun dieses File so einlesen, dass die Variablennamen sich an Spalte eins aus dem Textfile orientieren. Um bei diesem Beispiel zu bleiben sähen die Variablen also wie folgt aus:
name-1="hans" name-2="theo" produkt-1="auto" attribut-3="schoen"
Ferner möchte ich darüber dann ein case statement laufen lassen der Form: case $INHALT in $name-1|$name-2|$produkt-1|$attribut-3) ...
Hat jemand eine Idee wie man das elegant in Bash lösen kann?
Danke und Grüße Stefan
-- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Friday, November 26, 2010 17:20:21 C.M. Burns wrote:
Vorweg die Ausgangslage. Ich habe eine LIste als Textfile vorliegen im Format
name-1 hans name-2 theo produkt-1 auto attribut-3 schoen ...
Jede Zeile kann also unterschiedlich beginnen und das File kann quasi beliebig lang sein.
Ich möchte in einem Bash Skript nun dieses File so einlesen, dass die Variablennamen sich an Spalte eins aus dem Textfile orientieren. Um bei diesem Beispiel zu bleiben sähen die Variablen also wie folgt aus:
name-1="hans" name-2="theo" produkt-1="auto" attribut-3="schoen"
Ferner möchte ich darüber dann ein case statement laufen lassen der Form: case $INHALT in $name-1|$name-2|$produkt-1|$attribut-3) ...
Hat jemand eine Idee wie man das elegant in Bash lösen kann?
Du hast zwar geschrieben, es handle sich um eine Bash, aber nicht, um welche Version. Eine ausreichend aktuelle vorausgesetzt, kann auch die Bash assoziative Arrays: Speichern wir erstmal Deine Ausgangslage in einer Variablen, so brauche ich keine zusätzliche Datei: $ IN='name-1 hans'$'\n''name-2 theo'$'\n''produkt-1 auto'$'\n''attribut-3 schoen' $ cat <<<"$IN" name-1 hans name-2 theo produkt-1 auto attribut-3 schoen Nun lesen wir das in ein assoziatives Array ein: $ declare -A hash $ while read k v; do hash["$k"]="$v"; done <<<"$IN" Ein Test, ob name-1 gesetzt ist: $ echo "${hash[name-1]}" hans Die Anzahl der Elemente im Array: $ echo "${#hash[@]}" 4 Die Liste der Schlüssel (Indices): $ echo "${!hash[@]}" name-2 name-1 attribut-3 produkt-1 Nun Dein case Statement: $ INH=theo $ case "$INH" in "${hash[name-1]}") echo name-1;; "${hash[name-2]}") echo name-2;; *) echo neither name-1 nor name-2;; esac name-2 Und nochmal mit einem unbekannten Wert: $ INH=thecs $ case "$INH" in "${hash[name-1]}") echo name-1;; "${hash[name-2]}") echo name-2;; *) echo neither name-1 nor name-2;; esac neither name-1 nor name-2 Ist die Bash zu alt, könntest Du richtige Variablen statt eines Arrays benutzen, die Du mit eval setzt, ungefähr so: while read k v; do eval "$k"=\'"$v"\'; done Das funktioniert aber nur, wenn Deine Namen gültige Bash-Variablennamen sind. Deine fallen alle durch, da sie ein Minus enthalten. Alternativ müsstest Du die Datei halt mehrfach lesen. Dann könntest Du auch grep z.B. zum Filtern einsetzen. Außerdem ist eine named Pipe hilfreich, damit Du nicht aus einer anonymen Pipe lesen musst. Sowas hier "grep <<<"$IN" ^name-2 | read k v" würde nämlich nicht funktionieren, da der read-Befehl in einer Subshell ausgeführt wird und demzufolge auch die Variablen dort setzt. $ mkfifo ~/FIFO $ grep <<<"$IN" ^name-1 >~/FIFO & [1] 20528 $ read k v <~/FIFO $ echo $k name-1 [1]+ Done grep ^name-1 <<< "$IN" > ~/FIFO $ echo $v hans Also, Du kannst in der Bash möglicherweise Dein Problem lösen. Trotzdem würde ich es nur machen, wenn ich relativ gut kontrollieren kann, dass in der Input-Datei nur gutartige Daten stehen. Torsten Förtsch -- Need professional modperl support? Hire me! (http://foertsch.name) Like fantasy? http://kabatinte.net -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Torsten Förtsch schrieb:
Du hast zwar geschrieben, es handle sich um eine Bash, aber nicht, um welche Version. Eine ausreichend aktuelle vorausgesetzt, kann auch die Bash assoziative Arrays:
Speichern wir erstmal Deine Ausgangslage in einer Variablen, so brauche ich keine zusätzliche Datei:
$ IN='name-1 hans'$'\n''name-2 theo'$'\n''produkt-1 auto'$'\n''attribut-3 schoen' $ cat <<<"$IN" name-1 hans name-2 theo produkt-1 auto attribut-3 schoen
Nun lesen wir das in ein assoziatives Array ein:
$ declare -A hash $ while read k v; do hash["$k"]="$v"; done <<<"$IN"
Ein Test, ob name-1 gesetzt ist:
$ echo "${hash[name-1]}" hans
Die Anzahl der Elemente im Array:
$ echo "${#hash[@]}" 4
Die Liste der Schlüssel (Indices):
$ echo "${!hash[@]}" name-2 name-1 attribut-3 produkt-1
Nun Dein case Statement:
$ INH=theo $ case "$INH" in "${hash[name-1]}") echo name-1;; "${hash[name-2]}") echo name-2;; *) echo neither name-1 nor name-2;; esac name-2
Und nochmal mit einem unbekannten Wert:
$ INH=thecs $ case "$INH" in "${hash[name-1]}") echo name-1;; "${hash[name-2]}") echo name-2;; *) echo neither name-1 nor name-2;; esac neither name-1 nor name-2
Ist die Bash zu alt, könntest Du richtige Variablen statt eines Arrays benutzen, die Du mit eval setzt, ungefähr so:
while read k v; do eval "$k"=\'"$v"\'; done
Das funktioniert aber nur, wenn Deine Namen gültige Bash-Variablennamen sind. Deine fallen alle durch, da sie ein Minus enthalten.
Alternativ müsstest Du die Datei halt mehrfach lesen. Dann könntest Du auch grep z.B. zum Filtern einsetzen. Außerdem ist eine named Pipe hilfreich, damit Du nicht aus einer anonymen Pipe lesen musst.
Sowas hier "grep <<<"$IN" ^name-2 | read k v" würde nämlich nicht funktionieren, da der read-Befehl in einer Subshell ausgeführt wird und demzufolge auch die Variablen dort setzt.
$ mkfifo ~/FIFO $ grep <<<"$IN" ^name-1 >~/FIFO & [1] 20528 $ read k v <~/FIFO $ echo $k name-1 [1]+ Done grep ^name-1 <<< "$IN" > ~/FIFO $ echo $v hans
Also, Du kannst in der Bash möglicherweise Dein Problem lösen. Trotzdem würde ich es nur machen, wenn ich relativ gut kontrollieren kann, dass in der Input-Datei nur gutartige Daten stehen.
Torsten Förtsch
Ah, das assoziative Array war genau das was ich gesucht habe, ich hatte das testweise mal mit cat file|while read varname varvalue;do declare $varname=$varvalue; done; versucht. Das funktioniert soweit auch, aber dann hatte ich ja das Problem, dass mir ohne Hilfskonstrukt nicht bekannt war, welche Variablennamen existieren. Danke an die hilfsbereiten Leute, insbesondere Torsten! Kein Dank an die Realnamen Fetischisten, die ohnehin nicht prüfen können ob das nun der richtige Name ist oder nicht. Ich sollte einfach mal irgendeinen trollfreundlichen "Klaus Gerber" oder "Hans Höckel" eintragen damit hier Ruhe herrscht. Stefan -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
participants (4)
-
C.M. Burns
-
David Haller
-
Mike Philipp
-
Torsten Förtsch