• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[erledigt] Variablenzuweisung in einer Schleife

Escho

Advanced Hacker
Hallo

Ich möchte in einer Schleife verschiedenen Variablen unterschiedliche Werte zuweisen:
Code:
#!/bin/bash
 
hilfsprogramm=( mplex dvdauthor ProjectX )
for var in ${hilfsprogramm[*]}
do
    $var="/usr/bin/$var"
done
Das Ergebnis:
Code:
edgar@linux-2ljt:~> sh testscript
testscript: Zeile 7: mplex=/usr/bin/mplex: Datei oder Verzeichnis nicht gefunden
testscript: Zeile 7: dvdauthor=/usr/bin/dvdauthor: Datei oder Verzeichnis nicht gefunden
testscript: Zeile 7: ProjectX=/usr/bin/ProjectX: Datei oder Verzeichnis nicht gefunden
Geht sowas nicht, daß ich die Variablen, denen ein Wert zugewiesen werden soll selbst in einer Variablen stehen habe? Das Ergebnis wird ja offensichtlich als kompletter String interpretiert, nicht aber als Variablenzuweisung.

Edgar
 

HBtux

Member
Wenn ich Dich richtig verstanden habe, sollte das Deine Lösung sein....
Code:
#!/bin/bash

hilfsprogramm="mplex dvdauthor ProjectX"

for var in ${hilfsprogramm}
do
    pfad="/usr/bin/$var"
    echo Aktueller Wert $pfad
done
 

framp

Moderator
Teammitglied
Meinst Du vielleicht folgende Semantik?
Code:
#!/bin/bash

hilfsprogramm=( mplex dvdauthor ProjectX )
for var in ${hilfsprogramm[*]}
do
    eval $var='/usr/bin/$var'        # setze var mplex etc zu /usr/bin/mplex
    eval "deref=\${$var}"            # hole den Inhalt von var mplex in var deref
    echo "Inhalt von $var ist $deref"       # gib variable deref (dereferenzierte variable mplex, also deren Inhalt) aus
done
?
 
OP
Escho

Escho

Advanced Hacker
@HBtux
Nein so meine ich das nicht. Ich möchte vielmehr, daß die Variable (bei dir pfad) auch variabel ist. Ausgeschrieben ohne Schleife würde das so aussehen:
Code:
mplex=/usr/bin/mplex
dvdauthor=/usr/bin/dvdauthor
usw.
In meinem Script ( http://www.linupedia.org/opensuse/Dvb_script_gui/scriptcode (Ziemlich am Anfang in den Abschnitten Hilfsprogramme festlegen und Hilfsprogramme laden) läuft nämlich schon so eine Schleife und es wäre schön, diese Variablenzuweisung mit in der Schleife unterbringen zu können und nicht erst danach zu machen.
Übrigens, ich starte mit sh, weil ich die Bashdatei nicht ausführbar gemacht habe. Wenn ich auf die Datei draufdrücke, wird sie nun nämlich mit kate zum Editieren geöffnet. Reine Bequemlichkeit, wie ich zugeben muß. ;)

@framp
Das mit eval und deref muß ich erstmal nachlesen, was diese Anweisungen genau machen. Danach probier ich deinen Vorschlag aus und berichte. Das hast du zwar schön kommentiert, aber ich bin neugierig.

Edgar
 

abgdf

Guru
Uhh, das ist aber ganz übler Programmierstil!

(Obwohl sowas ähnliches in allen Sprachen immer mal wieder (von Anfängern) gefragt wird, z.B.:

http://www.perl-community.de/bat/poard/thread/7813
http://www.python-forum.de/topic-20607.html
)

Lös' das bitte irgendwie anders.

Gruß
 
OP
Escho

Escho

Advanced Hacker
abgdf schrieb:
Uhh, das ist aber ganz übler Programmierstil!
Lös' das bitte irgendwie anders.
Gruß
Was, das mit der Schleife oder das mit eval? das mit eval hab ich nämlich grad ausprobiert. Das würde funktionieren:
Code:
#!/bin/bash
 
hilfsprogramm=( mplex dvdauthor ProjectX )
for var in ${hilfsprogramm[*]}
do
    eval $var="/bin/$var"  
done
echo $mplex
echo $dvdauthor
echo $ProjectX

Edgar
 
OP
Escho

Escho

Advanced Hacker
Interessenter Artikel. Ich bau eval auch noch nicht in mein Script ein, bevor ich nicht genau weiß, was das alles bewirken kann. Ich bin noch am Suchen und am Testen, denn dadurch würde mein Script an Flexibilität gewinnen, wenn neue Hilfsprogramme dazukommen oder wegfallen. Und wenn ich nichts finde, dann lass ich es halt, so wie es ist.

Edgar
 

abgdf

Guru
Ich meine, wenn Du das in Deinem eigenen Skript so machen willst und das für Dich klappt, na gut.
Es wäre aber eben besser sich sowas gar nicht erst anzugewöhnen: Stell' Dir doch mal vor, jemand anders sollte Dein Skript lesen und verstehen. Er müßte dann jedesmal herausfummeln, wie Deine Variablen dann gerade heißen. Sehr unverständlich.
Damian Conway in 'Perl Best Practices' schrieb:
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
:mrgreen:

Gruß
 

framp

Moderator
Teammitglied
abgdf schrieb:
Uhh, das ist aber ganz übler Programmierstil!
Ganz so krass würde ich das nicht ausdrücken :roll: .
Hast Du mal Listenverarbeitung gemacht? Da ist z.B. in C ein Pointer auf einen Pointer die Art und Weise, wie man sich an den Listen elegant entlanghangelt. In der bash geht das nur über eval. Aber ich stimme Dir zu - solcher Code ist nicht auf den ersten Blick verständlich und muss gut dokumentiert werden. Dann aber ist es eine elegante Lösung für ein Problem. Also nicht gleich alles verteufeln ;)

Ob bei Escho das aber in seinem konkreten Anwendungsfall sinnvoll ist weiss ich nicht. Er müßte dann ein Array benutzen, in dem die Variablennamen stehen und diese dann dereferenzieren um variable zu sein.
 
OP
Escho

Escho

Advanced Hacker
abgdf schrieb:
Damian Conway in 'Perl Best Practices' schrieb:
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
Gruß
Da hilft nur eines: Schneller sein und rechtzeitig umziehen.

Ich weiß noch nicht genau, was ich mache. Mal schaun. Nur ändern werde ich was, um mehr Flexibilität zu bekommen. Das muß bei mir noch etwas reifen. ;)

Edgar
 

framp

Moderator
Teammitglied
Escho schrieb:
... Nur ändern werde ich was, um mehr Flexibilität zu bekommen. Das muß bei mir noch etwas reifen. ;)
Jupp - so sehe ich das auch. Dein Beispiel ist noch fixed mit den 3 Variablen und da macht es keinen Sinn diesen eval Ausflug zu machen. Wenn Du aber mit beliebigen Variablen arbeitest rechtfertigt sich das.

Allerdings muss ich gestehen, dass ich nicht so richtig verstehe, was Du da machen willst. Vielleicht geht es ja auch ohne den eval Ausflug :roll:
 
OP
Escho

Escho

Advanced Hacker
Also Sinn hätte das Ganze schon gemacht, auch wenn im Moment nur 8 Variablen zu handeln wären. Dennoch werde ich mir einen anderen Weg überlegen müssen, da sich ein Hindernis ergeben hat. Einer der Variablennamen würde namlich heißen:
Code:
ProjectX.jar
Und ein Punkt im Variablennamen geht nicht, da nicht erlaubt. Also lasse ich das DVB-Script erst einmal so wie es ist. Funktioniern tut es ja (Ich habe bereits über 150 DVDs damit erstellt und gebrannt ohne eine einzige Fehlbrennung).

Ich bedanke mich für die interessanten Hiweise und kann feststellen, daß ich wieder einiges dazugelernt habe.

Edgar
 
A

Anonymous

Gast
Also wenn du mich fragst ;)

ich würde aus dem ganzen Abschnitt "# Hilfsprogramme festlegen" die Komplexität komplett zusammenstreichen und herausnehmen.
Begründung:

  • 1. wer hat schon mehrere Versionen ein und des selben Programmes auf dem Rechner, die wenigsten
    2. wer wirklich mehrere Versionen auf dem Rechner hat, der kann auch mit der PATH-Variable umgehen
    3. so wie das Script an dieser Stelle gewachsen ist, ist es so schon kaum noch in kurzer Zeit verständlich lesbar, wenn jetzt hier noch komplizierte Verfahren dazukommen wird es einfach nur kaotisch oder sogra für andere überhaupt nicht mehr wartbar.
    4. das ganze ist ein Nebenschauplatz, heb dir die Kreativität für die Stellen im Script auf, wo sie benötigt wird, bei der Funktionalität

Vorschlag was ich mal probieren würde:

Code:
prog1=${PROG1:-$(which prog1)} ; echo "prog1 = ${prog1:?"prog1 nicht gefunden"}"
prog2=${PROG2:-$(find / -name prog2)} ; echo "prog2 = ${prog2:?"prog2 nicht gefunden"}"
prog3 .........
und das für alle Hilfsprogramme die benötigt werden, also für jedes Hilfsprogramm eine Zeile.

kurze Erklärung:
es wird über die PATH-Variable nach den Programmen gesucht, oder über andere Befehle danach gesucht.
sind mehrere Programmversionen auf dem Rechner, kann der User das entweder über die PATH-Variable steuern oder auch vor dem Scriptstart auf der Konsole das zu verwendente Programm vorgeben zB mit
Code:
export PROG1=/opt/test/bin/prog1
oder auch bei Programmaufruf kann man das mit angeben
Code:
PROG1=/opt/test/bin/prog1 bash script.sh
wird letztlich kein Programm mit which (oder mit anderen definierten Befehlen gefunden) und auch keines vor dem Aufruf fest zugewiesen, dann gibt es eine entsprechende Fehlermeldung, und da es eine interaktive Shell ist, bricht das Script an dieser Stelle ab.

oder anderer Vorschlag oder noch zusätzlich einbinden:
eine versteckte Konfigurationsdatei in der du die Programme fest eintragen kannst die verwendet werden sollen.
Das läßt sich mit dem obrigen auch verbinden, so das du in diese Konfigurationsdatei die du dann einbindest die Variabel Zuweisungen vornimmst.


robi
 
OP
Escho

Escho

Advanced Hacker
Servus robi

Schön daß du wieder einmal einen Blick auf mein Script geworfen hast. Wenn ich ehrlich bin, hatte ich schon mit dem Gedanken gespielt, diese ganze Erkennungsschleife rauszuwerfen. Gerade eben, bevor ich deinen Beitrag gelesen habe, habe ich mir mit export angesehen, was bei OpenSuse 11.2 alles in PATH drinsteht.

Ich weiß, daß das Script ziemlich umfangreich ist und manche Dinge enthält, bei denen es nicht auf den ersten Blick ersichtlich ist, warum das so ist. Aus diesem Grund habe eine Programmieranleitung geschrieben, in der das DVB-Script bis ins kleinst Detail erklärt ist. Eine Wartung sollt also kein allzu großes Problem sein.

Warum habe ich sie also noch nicht herausgeschmissen, die Schleife? Nun das hat im wesentlichen zwei Gründe:

Der erste Grund ist ProjectX. Dieses Programm habe ich aus gewissen Gründen in unterschiedlichen Versionen auf der Festplatte. Und das Script frägt mich bei der Erstinstallation, welche Version davon ich haben will. Da brauch ich nicht viel denken, sendern klicke die Version an und fertig. Das ist Bequemlichkeit für mich, nichts anderes.

Der zweite Grund ist die Schleife selbst. Es hat mir als gelerntem Nichtprogrammierer unheimlichen Spass bereitet, diese Programmerkennung funktionsfähig zu gestalten. Und das hat einigen Kampf gekostet, das darfst du mir glauben.

Nun, wie dem auch sei: Die Zeit steht nicht still und es fällt uns immer wieder neues ein, um altes zu optimieren.

Das Script aus dem Wiki-Buch betrachte ich als abgeschlossen. Ich werde es so lassen, wie es ist und nur noch so weit warten, daß es lauffähig bleibt.
Das Script mit der GUI, das aus dem Wikibuch-Script hervorgegangen ist, werde ich weiter entwickeln. Ich denke, daß die Erkennungroutine, so wie sie jetzt ist, hier demnächst fällt. Dann schmeisse ich noch die Playlist raus, die läuft mit einem eigenständigen kleinen Script wesentlich angenehmer. Und dann schauen wir weiter, was mir noch so einfällt.

Es gibt noch viel zu tun

Edgar
 

abgdf

Guru
@Escho: Was Du wohl im Grunde möchtest (und was auch die meisten möchten, die sowas vorschlagen) ist das, was man in Python ein "Dictionary" nennt: Eine Variable, in der wie in einem Wörterbuch Daten durch Schlüssel-Wert Paare verwaltet werden.
Mal ein Beispiel mit ein paar Englisch-Vokabeln in einem Dictionary, dann Dein Beispiel:
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

englischwbuch = { "do" : "tun",
                  "go" : "gehen",
                  "run": "laufen" }

for i in englischwbuch.keys():
    print "Der Wert für '" + i + "' ist '" + englischwbuch[i] + "'."

print
##############

keylist = ('mplex', 'dvdauthor', 'ProjectX')

hilfsprogramme = {}

for var in keylist:
    hilfsprogramme[var] = "/usr/bin/" + var

for i in hilfsprogramme.keys():
    print "Der Wert für '" + i + "' ist '" + hilfsprogramme[i] + "'."
In Perl heißt derselbe Datentyp "Hash":
Code:
#!/usr/bin/perl

use warnings;
use strict;

my %englischwbuch = ( "do"  => "tun",
                      "go"  =>  "gehen",
                      "run" =>  "laufen" );

foreach my $i (sort(keys(%englischwbuch))) {
    print "Der Wert für '$i' ist '$englischwbuch{$i}'.\n";
}

print "\n";
##############

my @keylist = ('mplex', 'dvdauthor', 'ProjectX');

my %hilfsprogramme;

foreach my $var (@keylist) {
    $hilfsprogramme{$var} = "/usr/bin/$var";
}

foreach (sort(keys(%hilfsprogramme))) {
    print "Der Wert für '$_' ist '$hilfsprogramme{$_}'." . "\n";
}
Bash bietet sowas leider nicht direkt. Manche versuchen es zu emulieren. Aber eigentlich sind solche komplexen Datentypen nicht in bash vorgesehen. Muß man mehr Datenverarbeitung machen als Arbeit mit Dateien, ist es sicher besser, eine der oben genannten Sprachen zu verwenden.

Viele Grüße
 

framp

Moderator
Teammitglied
@abgdf
Mir ist immer noch nicht klar was Escho eigentlich genau bewirken will. Sofern er wirklich hashes benötigt stimme ich Dir absolut zu. Mit hashes in der bash zu arbeiten ist von der Sprache nicht explizit unterstützt und cumbersome. Aber man kann ja perl oder python auch von der bash aufrufen wenn man mal hashes benötigt :roll:
 
OP
Escho

Escho

Advanced Hacker
Hallo zusammen

Das mit dem python und dem perl hat einen kleinen Haken: Ich beherrsche weder das eine noch das andere und kann es deshalb auch nicht einsetzen.

Bei dem Ganzen ging es um das DVB-Script aus unserer Linupedia ( http://www.linupedia.org/opensuse/Dvb_wiki_script/Script ), und zwar um die Abschnitte "Hilfsprogramme festlegen" (Zeilen 30 - 71) und "Hilfsprogramme laden" (Zeilen 73 - 82).
Meine Intention war es, den Abschnitt "Hilfsprogramme laden" mit in der var-Schleife erledigen zu lassen und damit den ganzen Lade-Abschnitt zu sparen. Der Befehl in der Schleife wäre folgender gewesen:
Code:
$var=`cat $ini_verz/$var`/$var
Ob es sinnvoll gewesen wäre steht auf einem anderen Blatt. Ich wollte nur wissen, ob diese Art der Variablenzuweisung in der Bash möglich ist. Und ich habe von euch erfahren, daß es mit eval funktionieren würde und auch klappt. Ich habs ausprobiert.

Und hier ist der zweite Haken ins Spiel gekommen: ProjectX.jar kann nicht als Variable angelegt werden, da ein Punkt im Variablennamen nicht erlaubt ist. Was zur Folge hat, daß mein Vorhaben mit einfachen Bash-Mittel nicht funktionieren kann.

Ich habs inzwischen anders gelöst, indem ich die Suche aus dem Script gestrichen habe und mich darauf beschränke, feststellen zu lassen, ob die Hilfsprogramme installiert sind. (http://www.linupedia.org/opensuse/Dvb_script_gui/scriptcode)

Soviel nur zur Info

Edgar
 

framp

Moderator
Teammitglied
Escho schrieb:
Und hier ist der zweite Haken ins Spiel gekommen: ProjectX.jar kann nicht als Variable angelegt werden, da ein Punkt im Variablennamen nicht erlaubt ist. Was zur Folge hat, daß mein Vorhaben mit einfachen Bash-Mittel nicht funktionieren kann.
Den Punkt sowie alle weiteren special Chars in der bash könnte man noch escapen und dann würde auch Dein Punkt akzeptiert werden. :roll: Nichts ist unmöglich bei Linux :D Wenn es aber anders geht ist es sicherlich besser.
 
Oben