Laurenz Trossel <m...@example.invalid>:
>On 2022-08-05, Juergen Ilse <
ne...@usenet-verwaltung.de> wrote:
>> Peter Blancke <
bla...@gmx.de> wrote:
>>> ,----
>>> |1 while read i; do
>>> |2 echo $i | grep "DAS HIER SUCHE ICH" &&
>>> |3 ( echo "KENNUNG0815 Meldung: $i " |
>>> |4 telnet
zuhause.example.com 11111 > /dev/null );
>>> |5 done < <(tail -f /var/log/mail.log)
>>> `----
>>
>> Das koennte gefaehrlich sein, wenn die eingelesene Zeile
>> unerwartete Zeichenkennten enthaelt ... Wenn z.B. etwas wie "$(rm
>> -rf $HOME)" darin vorrkaeme (ist bei Logs eher unwahrscheinlich),
>> koennte es dichh dein Home Verzeichnis einschliesslich aller
>> Inhalte kosten ...
>
>Wie funktioniert das?
>
>
># i='$(rm -rfv /tmp/foo)'
># echo $i
>$(rm -rfv /tmp/foo)
>
Wie du vermutest und dein Versuch zeigt, funktioniert es nicht.
Funktionieren würde
i='$(rm -rfv /tmp/foo)'
eval echo "$i"
obwohl bei der Zuweisung an die Variable «i» Apostrophe und bei der
Auswertung der Variablen «i» Anführungszeichen verwendet werden, und
zwar aus folgendem Grund:
Mit «eval» lässt der Shell den Kommandozeilen‐Parser auf die bereits
geparste Kommandozeile los. Im einzelnen geschieht folgendes:
Zunächst parst der Shell – wie gewohnt – die Kommandozeile
eval echo "$i"
und erkennt dabei, dass es sich bei dem Kommando in der
Kommandozeile um ein sogenanntes «simple command», also um ein
einfaches Kommando, das keine weiteren Konstrukte (compound
commands) wie «if», «while», «until» und «for», keine geklammerten
Kommandos wie «( … )» und «{ … }» (grouping commands), keine
bedingten Kommandos wie « … && …» und «… || …» und keine Pipes «… |
…» verwendet, handelt.
Ein simple command wird verarbeitet, indem die Kommandozeile in
Wörter zerlegt wird. Variablenzuweisungen und Ein‐ und
Ausgabeumlenkungen (beide in diesem Beispiel nicht enthalten) werden
speziell verarbeitet. Dann wird das erste Wort (also das ganz
links) darauf hin untersucht, ob es der Name eines Aliasses, einer
Shell‐Funktion, eines in den Shell eingebauten Kommandos oder eines
externen Programms ist.
Ist es der Name eines externen Programms, erzeugt der Shell eine
Prozesskopie von sich selbst (mit dem Systemaufruf «fork»); die
Shell‐Prozesskopie schließlich startet den Systemaufruf «execve» und
übergibt ihm als Parameter den Dateinamen der Programmdatei (damit
«execve» weiß, welches Programm es laden und starten soll) und eine
Parameterliste für das zu startende Programm, die aus dem
Namen des Programms als ersten Parameter (damit das laufende
Programm sehen kann, wie es heißt) und allen weiteren Wörtern
ebenfalls als je einzelnen Parameter besteht.
Ist das erste Wort der Kommandozeile kein externes Programm sondern
wird vom Shell selbst ausgeführt, tut der Shell nur so, als wäre es
ein externes Programm: «fork» und «execve» unterbleiben, aber das
Errichten einer Parameterliste wird wie oben durchgeführt, und der
Shell erledigt die Aufgabe des Kommandos anschließend selbst.
Aus
eval echo "$i"
entsteht also das simple command mit dem Namen «eval» und den beiden
zusätzlichen Parametern «echo» und «$(rm -rfv /tmp/foo)». Und jetzt
kommt die Semantik von «eval» ins Spiel:
«eval» klebt alle seine Parameter mit je einer Leerstelle zwischen
den einzelnen Parametern zusammen. So entsteht der folgende Text:
«echo $(rm -rfv /tmp/foo)»
Und dann lässt es den Shell‐Parser auf den Text los, nimmt ihn also
als Kommandozeile her. Damit wird
«echo $(rm -rfv /tmp/foo)»
als Kommandozeile zerlegt und interpretiert.
Dass die Kommandozeile
echo $(rm -rfv /tmp/foo)
gefährlich ist – habe ich aus den Beiträgen hier den Eindruck – hat
jeder verstanden, richtig? (Falls nicht, fragt nach.)