Re: Problem mit eval in script

From: Oliver Fromme <olli(at)lurza.secnetix.de>
Date: Fri, 20 May 2005 15:07:36 +0200 (CEST)

Sven Amonat <schorsch(at)justmail.de> wrote:
> Manfred Lotz wrote:
> > [ Env-Variablen mit dynamischen Namen erzeugen ]
> > Wenn aber der Inhalt der Variable Blanks enthält, geht es nicht mehr:
> >
> > #! /bin/sh
> > ind=1
> > eval HUGO$ind="to be or not to be"
>
> Das Problem ist, dass hier bei der Auswertung die Anführungszeichen
> "verschwinden".

Stimmt. Um es ein wenig zu präzisieren: Das »eval« be-
wirkt, daß die Anweisung (nach Expansion der Variablen)
ein zweites mal von der Shell geparst werden. Da aber
die Anführungszeichen schon beim ersten Durchgang verwen-
det worden und somit entfernt worden sind, stehen beim
zweiten mal keine Anführungszeichen mehr da.

Man kann das sehr schön sehen, wenn man die /bin/sh mit
der Option -x ausführt. Die bewirkt, daß alle Kommandos
nach jedem Parse-Vorgang angezeigt werden (mit vorange-
stelltem "+"-Zeichen).

olli(at)home:~> sh -x
$ ind=1
+ ind=1
$ eval HUGO$ind="to be or not to be"
+ eval HUGO1=to be or not to be [1]
+ HUGO1=to be or not to be [2]
be: not found
$

Wie man sieht, sind die Anführungszeichen nach dem ersten
Parsen weg (Zeile [1]). Das eval-Kommando läßt die Shell
dann das Ergebnis erneut parsen (Zeile [2]), mit dem Er-
gebnis, daß ein Kommando namens »be« ausgeführt werden
soll, mit den vier Argumenten »or not to be« und der Vari-
ablen »HUGI1=to« im Environment.

Wer öfters in der Shell mit Quoting, eval usw. zu kämpfen
hat, sollte sich die Option -x unbedingt merken. Damit
läßt sich so mancher gordische sh-Knoten sehr leicht
durchschlagen.

> Ein
>
> eval HUGO$ind=\"to bo or not to be\"
>
> funktioniert.

Ja, aber nur zufällig. :-)

In dieser Version ignoriert der erste Parse-Vorgang die
Anführungszeichen und entfernt die Backslashes. Der zweite
Durchgang sieht dann die Anführungszeichen, der erste aber
nicht.

Das funktioniert in diesem Fall, weil es einfache Leerzei-
chen sind, an denen der Tokenizer der Shell (beim ersten
Parsen) White-Space-Splitting durchführt, und eval fügt
die einzenen Token dann -- durch einzelne Leerzeichen ge-
trennt -- wieder zusammen.

Würde man dagegen z.B. mehrfache Leerzeichen verwenden,
oder Tabs, dann gingen diese verloren:

$ eval HUGO$ind=\"to be or not to be\"
+ eval HUGO1="to be or not to be"
+ HUGO1=to be or not to be

Am besten ist es daher, die Anführungszeichen für _beide_
Stufen des Parsers zu verwenden (und zwar einfache Anfüh-
rungszeichen für die zweite Stufe). Das sieht nicht un-
bedingt hübsch aus, tut aber das Gewünschte und ist ro-
buster.

$ eval HUGO$ind=\'"to be or not to be"\'
+ eval HUGO1='to be or not to be'
+ HUGO1=to be or not to be
$

Dann dürfen sogar Zeilenende und andere seltsame Dinge im
Wert der Variablen enthalten sein -- allerdings muß man
aufpassen, wenn man den Wert einer anderen Variablen ver-
wenden will und dieser ebenfalls (einfache) Anführungs-
zeichen enthalten kann. Dann wird's ein wenig komplizier-
ter, denn man muß diese vorher escapen (z.B. mit sed(1)).
Man sollte sich dann evtl. überlegen, ob man das ganze
nicht doch besser in einer richtigen Programmiersprache
machen sollte, nicht in einer Skript-Sprache.

Im vorliegenden Fall wird das »eval« offenbar nur zur Emu-
lation von Arrays verwenden. Daher könnte man sich auch
überlegen, das ganze in einer Shell zu schreiben, die
Arrays native unterstützt, wie z.B. ksh oder zsh. Man
spart sich dann das »eval« und die ganzen Probleme, die
damit Zusammenhägen (übrigens auch Security-Probleme!).
Das Skript ist dann zwar nicht mehr ganz so portabel, aber
eine zsh oder bash (die beide das Array-Konzept von der
ksh abgeschaut haben) kann man sich im Bedarfsfall rasch
installieren, unter *BSD sowieso.

Eine weitere Alternative wäre natürlich awk(1) -- eine Art
vereinfachtes, interpretiertes C, das ebenfalls Arrays un-
terstützt und auf jedem System vorhanden sein sollte.

#!/usr/bin/awk -f
BEGIN {
        ind = 1
        HUGO[ind] = "to be or not to be"
}

Gruß
   Olli

-- 
Oliver Fromme, secnetix GmbH & Co KG, Oettingenstr. 2, 80538 München
Any opinions expressed in this message may be personal to the author
and may not necessarily reflect the opinions of secnetix in any way.
C++: "an octopus made by nailing extra legs onto a dog"
        -- Steve Taylor, 1998
To Unsubscribe: send mail to majordomo(at)de.FreeBSD.org
with "unsubscribe de-bsd-questions" in the body of the message
Received on Fri 20 May 2005 - 15:08:24 CEST

search this site