Hallo Ratti, * ratti schrieb am 13.Jun.2002:
Es sieht aus, als müsse ich mir da eine RE selber basteln. 8:-( Eigentlich fühle ich mich dafür gar nicht sicher genug. Gibt es irgendwo eine Liste aller "relevanten" Zeichen, die in sowas wie `mv $a $b` nicht vorkommen dürfen? Mir fällt dazu jetzt ein:
* ? [ ] { } > < | " ` ' ' ~ ...ohje, das ist ja fast alles zwischen ASCII 33 und 64.
Wieso sollen die da nicht vorkommen dürfen? Die dürfen alle als Inhalt der Variable vorkommen. Nicht direkt, das ist allerdings richtig. Aber das willst Du offensichtlich auch nicht. Aber als Inhalt der Variablen darf jedes Zeichen vorkommen, und es wird so genommen, wie es ist. Die `..` um das mv ergeben aber keinen rechten Sinn. `..` Bedeutet, ersetze die `..` mitsamt des Inhaltes durch die Ausgabe des Befehls, der innerhalb der `..` steht. Etwa a=`ls` Hierbei wird der Variablen a die Ausgabe von ls zugewiesen. mv hat aber gar keine Ausgabe, deshalb wird das `...` auch nur durch eine Leerzeile ersetzt. Der Effekt von mv bleibt natürlich erhalten.
Was mich wundert: Ich hatte eigentlich eine Fehlermeldung erwartet, wenn ich das hier machen:
touch a\"b # Datei erzeugen die heisst a"b
Und wieso? Der \ deckt doch das " ab. " hat doch nur in der Shell eine besondere bedeutung, nicht in mv, cp oder touch. Die Shell, die läuft interpretiert den \ und weiß, daß das nächste Zeichen so genommen wird, wie es da steht, es übergibt somit die Zeichenkette a"b an touch. touch interpretiert nicht am Namen herum, sondern nimmt es so wie es ist. Jeden Namen, alles, auch ein \ würde so genommen wie es ist. Aber den \ bekommt touch erst gar nicht zu Gesicht. Den verwurschtelt schon die Shell. Die Shell macht aus a\"b ein a"b und übergibt touch dieses a"b. Und touch legt eine Datei namens a"b an.
...und dann ein Script starte, das so aussieht:
a=`find ./ -name "a*"` echo $a mv "$a" "safename"
Ich hatte erwartet,
mv "$a" "safename" würde expandiert zu mv "a"b" "safename" und somit eine Fehlermeldung verursachen...
Nein, nein. Es wird nur einmal expandiert. "$a" wird mit dem Inhalt von $a ersetzt. Dieser Inhalt wird aber so wie er ist an dem Befehl weitergegeben. Der Befehl selber interpretiert nicht. Was anderes ist folgendes: Du kanst auch sowas machen: mv "$a" "$a.test" da wird dann einfach jeder Datei ein test angehangen. Hier mußt Du vorsichtig sein, wenn da nicht test stände, sondern etwa t\l oder so. Also: mv "$a" "$a.t\l" Denn wird der \ hier interpretiert. Aber die Variable wird so genommen, wie sie ist.
Verdammt! Immer wenn man denkt, man hätte es kapiert! =%-)
Es expandiert nur die Shell. Und nur einmal. Wenn Du es öfters haben möchtest, muß Du ein eval davor setzen. $ a='$b' $ b=test $ echo $a $b $ echo $b test $ eval echo $a test Die Befehle interpretieren normalerweise nicht nochmal. Außnahme ist hier etwa find. Beim find wird das was nach -name kommt so interpretiert, wie es auch die shell machen würde. Daher sollte auch in einem find das was nach -name kommt, in '...' gesetzt werden, damit die Shell es nicht schon vorher interpretiert. Ein grep interpretiert das 1.Argument nach den Options z.B als Suchmuster. Aber da hat der * eine ganz andere Bedeutung als in der Shell. In der Shell steht der * für beliebig viele beliebige Zeichen. Bei grep und anderen RegExp steht der * für beliebig häufige Wiederhohlung des letzten Zeichens. Aber auch hier sollte der Suchbegriff in '...' eingeschlossen werde, damit die Shell ein evtl. * nicht interpretiert. Das Problem, daß Du mit mv in Deiner letzten Mail hattes, ist kein Shell und Expansionsproblem. Du hattest versucht eine Datei einen Namen zu geben, der ein / enthält. Das funktioniert grundsätzlich nicht. Aber da hat die Shell nichts mit zu tun. Die Shell hat die Variable brav expandiert und es an mv übergeben. In dem Argument von mv kam aber ein / vor. mv interessiert sich auch nicht sonderlich dafür, sondern macht einfach einen Systemaufruf rename und übergibt die beiden Argumente. Nun aber tritt der Kernel himself in Kraft und verweigert die Anlegung eines Dateinamens, der ein / enthält. Du kanst Dich auf dem Kopf stellen, und mit den Füßen wackeln, aber Du wirst es nicht schaffen, eine Datei einen Namen zu geben, der einen / enthält, weil der Kernel es verweigert. Der Ersetzungsmechanismus der Shell: Die Shell ersetzt ein * durch beliebig viele, beliebige Zeichen. Aber immer nur so, daß sich Dateinamen aus dem aktuellen Verzeichnis ergeben. Steht im Verzeichnis etwa datei, datei1 und test, so macht die shell aus d* datei datei1 und aus *e* macht die shell datei datei1 test Daneben gibt es noch ? und {...} Konstrukte. $VARIABLE wird durch den Inhalt von VARIABLE ersetzt. Hier gibt es noch eine Reihe wunderschöner Möglichkeiten, etwa ${VARIABLE:-Wert} Wird durch den Inhalt der Variable VARIABLE ersetzt. Wenn sie aber leer ist, dann wird es mit Wert ersetzt. \ nimmt die Sonderbedeutung des nächsten Zeichens für die Shell weg. So wird \$ mit $ ersetzt, und nicht das nächste Wort als Variable interpretiert. \\ steht somit für das \ selbst. "..." innerhalb der "..." werden alle * und ? nicht expandiert. Es ist so, als stände vor jedem * und jedem ? ein \. Ebenfalls werden die ' nicht expandiert. Wohl aber werden die ` und die $ expandiert. Variablen innerhalb von "..." werden somit ersetzt. '...' innerhalb der '...' wird schier gar nichts expandiert, weder * und ? noch $ noch " oder ` noch nicht mal das \ wird expandiert. `...` alles was innerhalb der `...` steht wird als Befehl aufgefaßt und ausgeführt. Danach wird `...` durch die Ausgabe des Befehls ersetzt. Mit Ausgabe ist NB die Standardausgabe und nicht die Standardfehlerausgabe gemeint. Wie auch immer ersetzt wird. Es wird nur einmal ersetzt. Das Ergebnis wird dann genommen. Es wird nicht nochmal interpretiert. Es sei denn, es stände ein eval davor. Ist natürlich alles andere als Vollständig, soll nur was das Verständnis fördern. Und nochmal, die einzelnen Befehle, wie mv, cp, rm, touch, cat, sort ... expandieren nicht. Wenn bei denen sowas wie a*b ankommt, dann nehmen sie es auch so. Bernd