2016-04-01 6 views
1

Kann jemand dieses Verhalten erklären, wenn R extern von der Befehlszeile mit einem mehrzeiligen Stringargument aufgerufen wird?Zuweisungsproblem mit Rscript -e-Aufrufe

$ Rscript -e "dim(mtcars)" 
[1] 32 11 
$ Rscript -e "df = mtcars; dim(df)" 
[1] 32 11 
$ Rscript -e "head(rownames(mtcars))" 
[1] "Mazda RX4"   "Mazda RX4 Wag"  "Datsun 710" 
[4] "Hornet 4 Drive" "Hornet Sportabout" "Valiant" 
$ Rscript -e "df = mtcars; df$car = rownames(mtcars); dim(df)" 
NULL 
+1

Kleiner Punkt: Es wäre richtiger, es ein "Multi-Anweisung String-Argument" statt ein "Multi-Zeile String-Argument" zu nennen. – bgoldst

Antwort

4

Der Täter ist hier die Schale, nicht R.

Sie haben nicht angegeben, welche Shell Sie verwenden, aber sie alle (sh/bash/ash/dash/KSH/zsh/tcsh) verhalten sich ziemlich ähnlich für unsere Zwecke, so nehmen wir an, Sie bash verwenden, so kann ich die Hälfte der bash man page zitieren:

...

DEFINITIONEN

        Die folgenden Definitionen werden im Rest dieses Dokuments verwendet.

...

                Name         Ein Wort nur aus alphanumerischen Zeichen und Unterstrichen besteht, und mit einem Buchstaben oder einem Unterstrich beginnt. Wird auch als Kennung bezeichnet.

...

ANBIETEN

...

        Enclosing Zeichen in doppelten Anführungszeichen bewahrt die wörtliche Wert aller Zeichen innerhalb der Anführungszeichen, mit Ausnahme von $, ` , und, wenn die Verlaufserweiterung aktiviert ist, Die Zeichen $ und `behalten ihre spezielle Bedeutung in Anführungszeichen.

...

PARAMETERS

        Ein Parameter ist eine Einheit, die Werte speichert. Es kann ein Name, eine Zahl oder eines der Sonderzeichen sein, die unten unter Spezielle Parameter aufgeführt sind. Eine Variable ist ein Parameter, der durch einen Namen bezeichnet wird.

...

        Parameter Expansion

                Der `$‘ Zeichen stellt Parameter, Kommando-Substitution oder arithmetische Expansion. Der zu erweiternde Parametername oder das Symbol kann in geschweifte Klammern eingeschlossen sein, die optional sind, aber dazu dienen, die zu expandierende Variable vor unmittelbar folgenden Zeichen zu schützen, die als Teil des Namens interpretiert werden können.

...

        $ {parameter}

                Der Wert des Parameters ersetzt wird. Die geschweiften Klammern sind erforderlich, wenn der Parameter ein Positionsparameter mit mehr als einer Ziffer ist oder wenn auf einen Parameter folgt, der nicht als Teil seines Namens interpretiert werden soll. Der Parameter ist ein Shell-Parameter wie oben beschrieben (PARAMETERS) oder eine Array-Referenz (Arrays).

...

So nimmt Parameter Expansionseffekt innerhalb Strings in doppelten Anführungszeichen, und Sie haben eine unescaped durch einen gültigen Variablennamen in Ihrem Strings in doppelten Anführungszeichen gefolgt Dollar: $car.

Ich folge, dass die Variable $car in der Shell-Sitzung, in der Sie den anstößigen Befehl ausgeführt haben, nicht festgelegt wurde.

Das unglückliche Standardverhalten der Shell besteht darin, nicht festgelegte Variablen automatisch in die leere Zeichenfolge zu erweitern. So kann Ihr R Code endet in dieser verstümmelt werden:

df = mtcars; df = rownames(mtcars); dim(df) 

somit df mit einer dimensionslosen Zeichenvektor überschrieben wird, und dim(df) NULL zurück auf solche Vektoren.

Das Problem kann durch Backslash-Flucht aus dem Dollar gelöst werden:

Rscript -e "df <- mtcars; df\$car <- rownames(mtcars); dim(df);"; 
## [1] 32 12 

Oder noch besser, mit einfachen Anführungszeichen, die innerhalb des Strings in einfachen Anführungszeichen zu nicht jede Interpolation ermöglichen:

Rscript -e 'df <- mtcars; df$car <- rownames(mtcars); dim(df);'; 
## [1] 32 12 

auf eine persönliche Note, IMO, nur sehr wenige Ingenieure scheinen die Bedeutung von Strenge zu verstehen im Software-Design. Es wäre ein großer Dienst für den Computerprogrammierberuf gewesen, wenn die Shell entworfen worden wäre, um nicht festgelegte Variablen vom ersten Tag an abzulehnen, aber ach, das ist nicht der Fall. Und so arme Seelen wie du und ich und grundsätzlich jeder, der jemals eine Shell-Programmierung macht, gerät von Zeit zu Zeit in Konflikt mit diesen stillen Fehlern.

Zum Glück wurde eine optionale Funktion zur Shell frühen hinzugefügt am nounset genannt:

help set| grep -e nounset -e -u; 
##    nounset  same as -u 
##  -u Treat unset variables as an error when substituting. 

Wenn Sie es einschalten, die ich stark schlage vor, Sie tun, dann wird der säumige Rscript Befehl sofort hätte gescheitert und klar:

set -u; 
Rscript -e "df <- mtcars; df$car <- rownames(mtcars); dim(df);"; 
## -bash: car: unbound variable 
+2

Richtige Antwort und schön detailliert. Kurz gesagt, '' 'ist dein Freund wegen der fehlenden Interpolation. –

+1

Schöne Arbeit bgoldst - Bash Alchemie offiziell entlarvt .. – geotheory

Verwandte Themen