Was ist der Sinn von eval / bash -c, anstatt nur eine Variable zu bewerten?

8

Angenommen, Sie haben den folgenden Befehl in einer Variablen gespeichert:

%Vor%

Was ist der Unterschied zwischen

? %Vor%

? Warum wird die letzte Version fast nie benutzt, wenn sie kürzer ist und (soweit ich das sehen kann) genau dasselbe tut?

    
James Ko 23.12.2015, 01:22
quelle

3 Antworten

11

Die dritte Form ist überhaupt nicht wie die anderen beiden - aber um zu verstehen, warum, müssen wir in die Reihenfolge der Operationen gehen, wenn bash einen Befehl interpretiert, und schauen, welche davon bei jeder Methode befolgt wird verwenden.

Bash Parsing Stages

  1. Angebotsverarbeitung
  2. In Befehle aufteilen
  3. Analyse spezieller Operatoren
  4. Erweiterungen
  5. Wortaufteilung
  6. Globbing
  7. Ausführung

Verwendung von eval "$string"

eval "$string" folgt allen obigen Schritten ab # 1. Also:

  • Literale Anführungszeichen im String werden zu syntaktischen Anführungszeichen
  • Spezielle Operatoren wie >() werden verarbeitet
  • Erweiterungen wie $foo werden berücksichtigt
  • Die Ergebnisse dieser Erweiterungen werden in Leerzeichen in separate Wörter aufgeteilt
  • Diese Wörter werden als Globs erweitert, wenn sie gleich analysieren und verfügbare Übereinstimmungen haben, und schließlich wird der Befehl ausgeführt.

Verwendung von sh -c "$string"

... führt das gleiche aus wie eval , aber in einer neuen Shell, die als separater Prozess gestartet wird ; Änderungen am Variablenstatus, am aktuellen Verzeichnis usw. verfallen daher, wenn dieser neue Prozess beendet wird. (Beachten Sie auch, dass diese neue Shell möglicherweise ein anderer Interpreter ist, der eine andere Sprache unterstützt; dh sh -c "foo" unterstützt nicht die gleiche Syntax wie bash , ksh , zsh usw.).

Verwendung von $string

... beginnt mit Schritt 5, "Wortteilung".

Was bedeutet das?

Zitate werden nicht berücksichtigt.

printf '%s\n' "two words" wird also als printf %s\n "two words" analysiert, im Gegensatz zum üblichen / erwarteten Verhalten von printf %s\n two words (wobei die Anführungszeichen von der Shell verbraucht werden) ).

Die Aufteilung in mehrere Befehle (in ; s, & s oder ähnlich) findet nicht statt.

Also:

%Vor%

... gibt die folgende Ausgabe aus:

%Vor%

... anstelle der folgenden, die sonst erwartet würden:

%Vor%

Spezielle Operatoren und Erweiterungen werden nicht berücksichtigt.

Keine $(foo) , keine $foo , keine <(foo) , etc.

Umleitungen werden nicht berücksichtigt.

>foo oder 2>&1 ist nur ein anderes Wort, das durch String-Splitting und nicht durch eine Shell-Direktive erzeugt wird.

    
Charles Duffy 23.12.2015, 02:06
quelle
1
%Vor%

Diese Version startet einen neuen Bash-Interpreter, führt den Befehl aus und wird dann beendet, wobei die Steuerung an die ursprüngliche Shell zurückgegeben wird. Sie müssen überhaupt nicht zuerst bash ausführen, Sie können beispielsweise einen Bash-Interpreter von tcsh starten. Sie können dies auch über ein Bash-Skript tun, um mit einer neuen Umgebung zu beginnen oder um die aktuelle Umgebung nicht zu belasten.

BEARBEITEN:

Wie @CharlesDuffy darauf hinweist, dass das Starten einer neuen Bash-Shell auf diese Weise die Shell-Variablen löscht, aber Umgebungsvariablen von dem erzeugten Shell-Prozess geerbt werden.

Wenn eval verwendet wird, parst die Shell den Befehl zweimal. In dem Beispiel, das Sie angegeben haben, ist $ COMMAND direkt auszuführen oder ein eval ist äquivalent, aber werfen Sie einen Blick auf die Antwort hier um eine genauere Vorstellung davon zu bekommen, für was eval gut (oder schlecht) ist.

    
Turn 23.12.2015 01:36
quelle
1

Es gibt zumindest Zeiten, wenn sie anders sind. Berücksichtigen Sie Folgendes:

%Vor%

zeigt die verschiedenen Punkte, an denen die variable Erweiterung durchgeführt wird. Es ist noch deutlicher, wenn wir set -x first

machen %Vor%

Wir können hier viel von dem sehen, worüber Charles Duffy in seiner ausgezeichneten Antwort spricht. Wenn Sie zum Beispiel versuchen, die Variable auszuführen, wird $var direkt ausgegeben, weil die Parametererweiterung und diese früheren Schritte bereits durchgeführt wurden. Daher erhalten wir nicht den Wert von var , wie wir es mit eval tun.

Die Option bash -c erbt nur export ed -Variablen von der übergeordneten Shell, und da ich var nicht exportiert habe, ist sie für die neue Shell nicht verfügbar.

    
Eric Renouf 23.12.2015 01:32
quelle

Tags und Links

Django: Verwenden von Annotate, Count und Distinct in einem Queryset ___ tag123ios ___ iOS ist das mobile Betriebssystem, das auf dem Apple iPhone, iPod touch und iPad ausgeführt wird. Verwenden Sie dieses Tag [ios] für Fragen zur Programmierung auf der iOS-Plattform. Verwenden Sie die verwandten Tags [objective-c] und [swift] für Probleme, die für diese Programmiersprachen spezifisch sind. ___ tag123objectivec ___ Dieses Tag sollte nur bei Fragen verwendet werden, die sich auf Objective-C-Features beziehen oder von Code in der Sprache abhängen. Die Tags [Kakao] und [Kakao-Touch] sollten verwendet werden, um nach Frameworks oder Klassen von Apple zu fragen. Verwenden Sie die verwandten Tags [ios], [macos], [apple-watch] und [tvos] für Probleme, die für diese Plattformen spezifisch sind. ___ tag123swift ___ Swift ist eine universelle Open-Source-Programmiersprache, die von Apple Inc. für ihre Plattformen und Linux entwickelt wurde. Verwenden Sie das Tag nur für Fragen zu Sprachfunktionen oder für Code in Swift. Verwenden Sie die Tags [ios], [osx], [watch-os], [tvos], [cocoa-touch] und [cocoa] für (sprachunabhängige) Fragen zu den Plattformen oder Frameworks. ___ answer34444874 ___

Wenn Sie nur den Pfad zur Datei (und nicht eine Instanz von %code% ) benötigen, wird Folgendes gemacht:

%Vor%     
___ tag123path ___ Ein Pfad, die allgemeine Form eines Dateinamens oder eines Verzeichnisnamens, gibt einen eindeutigen Speicherort in einem Dateisystem an. In vielen Linux- und Unix-ähnlichen Betriebssystemen gibt die Variable PATH (alle Großbuchstaben) die Verzeichnisse an, in denen ausführbare Programme gesucht werden. ___ qstntxt ___

Versuchen Sie, den Pfad zu den Bildern mit schnellem Code zu ermitteln. Ich habe das, was meiner Meinung nach in Ziel C funktioniert.

%Vor%

Um den Pfad für mein .png Bild zu erhalten, habe ich in assets.xcassets gespeichert. Aber ich muss das jetzt in SWIFT tun, nicht in objektiven C.

Ich brauche den Pfad, weil ich versuche, das Bild, das ich dort eingefügt habe, auf ein %code% in iCloud hochzuladen.

    
___ tag123icloud ___ iCloud ist ein Webdienst von Apple Inc., mit dem Benutzer Daten wie Musikdateien speichern und automatisch zwischen mehreren Geräten wie iPhones, iPods, iPads und PCs synchronisieren können. Beachten Sie, dass iCloud eine andere API als Apples CloudKit-Dienst ist. ___