Ich habe einen Befehl in einer Variablen gespeichert. Stellen wir uns vor, die Variable $i
hat den Wert:
cat -nT index.php |grep 'someregex'
Wenn ich versuche, die obige Variable durch Eingabe auszuführen $i
, schlägt dies fehl, da die Shell versucht, die gesamte Variable als einen Befehl auszuführen. Ich habe auch versucht eval($i)
, $i
Backticks zu verwenden und einzufügen.
Wie kann ich die Shell so ausführen lassen, $i
als wäre es ein Befehl? Und warum funktioniert es nicht genauso wie.
$i='echo hi'; $i
Liegt es daran, dass ich die einzelnen Anführungszeichen irgendwie hacken musste? (Weil du sie nicht verschachteln kannst.) Derzeit ist meine Lösung
echo $i > /foo; . /foo
Aber ich möchte nicht nur dafür eine Datei erstellen, sondern sie später löschen.
Was ich mit "Ich habe in den einfachen Anführungszeichen gehackt" meine, habe ich getan:
$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
Antworten:
Kurze Antwort: siehe BashAQ # 50: Ich versuche, einen Befehl in eine Variable einzufügen, aber die komplexen Fälle schlagen immer fehl! .
Lange Antwort: Es liegt an der Reihenfolge, in der Bash die Befehlszeile analysiert. Insbesondere sucht es nach Dingen wie Pipes und Weiterleitungen, bevor es variable Werte erweitert, und geht nicht zurück und sucht in den erweiterten Werten erneut nach Pipes usw. Im Wesentlichen werden Variablen etwa zur Hälfte des Analyseprozesses ersetzt, sodass der Wert vor der Ausführung nur zur Hälfte analysiert wird.
Um dies zu lösen, müssen Sie die Frage von @ slhck beantworten: Warum wird der Befehl überhaupt in einer Variablen gespeichert? Was ist das eigentliche Problem, das Sie lösen möchten? Abhängig vom tatsächlichen Ziel gibt es eine Reihe möglicher Lösungen:
Speichern Sie es nicht in einer Variablen, sondern führen Sie es direkt aus. Das Speichern von Befehlen für die spätere Verwendung ist schwierig, und wenn Sie dies nicht wirklich benötigen, tun Sie es einfach nicht.
Verwenden Sie eine Funktion anstelle einer Variablen. Dafür sind sie schließlich da:
Der Hauptnachteil davon ist, dass Sie die Funktion nicht dynamisch erstellen können - Sie können Code nicht bedingt ein- oder ausschließen (obwohl die Funktion selbst bedingte Elemente enthalten kann, die bei der Ausführung ausgewählt werden).
Verwenden Sie
eval
. Dies sollte als letzter Ausweg betrachtet werden, da es leicht zu unerwartetem Verhalten kommt. Der Befehl wird im Wesentlichen durch einen weiteren vollständigen Parsing-Durchlauf ausgeführt, sodass alle Pipes usw. ihre volle Bedeutung erhalten. Dies bedeutet jedoch auch, dass Teile des Befehls, von denen Sie dachten, dass es sich nur um Daten handelt, ebenfalls analysiert und möglicherweise ausgeführt werden. Dateinamen, die Shell-Metazeichen (Pipe, Semikolon, Anführungszeichen / Apostroph usw.) enthalten, können seltsame und manchmal gefährliche Auswirkungen haben. Wenn Sieeval
die Zeichenfolge verwenden, zitieren Sie sie mindestens doppelt, andernfalls wird ihr Inhalt im Wesentlichen eineinhalb Mal analysiert, mit noch seltsameren Ergebnissen.BEARBEITEN: Ein anderer Standardansatz zum Speichern eines Befehls in einer Variablen besteht darin, ein Array anstelle einer einfachen Variablen zu verwenden. Auf diese Weise können Sie einen Befehl mit komplexen Argumenten (z. B. Leerzeichen) problemlos speichern, jedoch keine Elemente wie Pipes und Weiterleitungen. Daher ist der Array-Ansatz in diesem speziellen Fall nicht hilfreich.
quelle
eval
Methode. Dies hat mich davon abgehalten, die gleiche Frage zu stellen :). Ich habe so etwassudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-root
nicht richtig die Ausschlüsse ausgeführt.eval
es zu verwenden - es gibt zu viele Möglichkeiten, um etwas falsch zu machen. Ein Array wäre ein besserer Weg, dies zu tun. Beispiele finden Sie hier , hier und hier .Das sollte einfach funktionieren:
Beachten Sie, dass dies
eval
potenzielle Sicherheitslücken und unerwartete Verhaltenssituationen mit sich bringt und daher, wenn überhaupt, mit besonderer Sorgfalt verwendet werden muss.quelle
eval
, müssen Sie wirklich doppelte Anführungszeichen (eval "$i"
) verwenden, um besonders seltsame Effekte zu vermeiden. Versuchen Sie dies beispielsweise mita="cat -nT index.php |grep ' .* '"
(dh der reguläre Ausdruck sollte zwei Leerzeichen mit einer beliebigen Zeichenfolge zwischen ihnen übereinstimmen) und sehen Sie, was tatsächlich passiert. Erklären Sie für zusätzliche Gutschriften, warum dies geschieht.Wenn Sie die Variable deklarieren, sollten Sie das Dollarzeichen nicht als Präfix verwenden.
Versuche dies:
quelle