Perl: Ist quotemeta nur für reguläre Ausdrücke? Ist es sicher für Dateinamen?

8

Bei der Antwort diese Frage zum sicheren Entkommen von Dateinamen mit Leerzeichen (und möglicherweise anderen) Zeichen), eine der Antworten , die gesagt werden, die eingebaute Perl zu verwenden quotemeta Funktion.

Die Dokumentation von quotemeta besagt:

%Vor%

In der Dokumentation von quotemeta ist die einzige Erwähnung seiner Verwendung, dass alle Zeichen außer /[A-Za-z_0-9]/ mit einem \ für die Verwendung in einer Regex entfernt werden. Es gibt nicht die Verwendung für Dateinamen an. Dies scheint jedoch ein sehr angenehmer, wenn auch undokumentierter Nebeneffekt zu sein.

In einem Kommentar zu Sinan Ünür antworten auf die frühere Frage, Hobbs sagt:

  

shell escaping unterscheidet sich von   Regexp entkommt, und obwohl ich nicht kann   mit einer Situation, wo   quitemeta würde ein wirklich unsicheres geben   Ergebnis, es ist nicht für die Aufgabe bestimmt.   Wenn du fliehen musst, statt   Um die Hülle zu umgehen, schlage ich vor, es zu versuchen   String :: ShellQuote, das mehr dauert   konservativer Ansatz mit sh single   Zitate um alles außer allem zu defangieren   einfache Anführungszeichen selbst, und   Backslashes für einfache Anführungszeichen. - Hobbs   13. August 09 um 14:25

Ist es sicher - vollständig -, anstelle einer konservativeren Datei, die wie String :: Shellquote ? Ist quotemeta utf8 oder Multibyte-Zeichen sicher?

Ich habe einen Test zusammengestellt, der unklar ist. quotemeta funktioniert gut, es scheint, abgesehen von einem Dateinamen oder Verzeichnisnamen mit einem \n oder \r darin. Obwohl diese Zeichen selten sind, sind sie in Unix legal und ich habe sie gesehen. Erinnern Sie sich daran, dass bestimmte Zeichen wie LF, CR und NUL nicht mit \ maskiert werden können. Ich habe meine Festplatte mit 700k-Dateien mit Zitat gelesen und hatte keine Fehler.

Ich habe Verdacht (obwohl ich es noch nicht demonstriert habe), dass quotemeta mit Multibyte-Zeichen fehlschlagen könnte, bei denen ein oder mehrere Bytes in den ASCII-Bereich fallen. Zum Beispiel kann à als ein Zeichen (UTF8 C3 A0) oder als zwei Zeichen codiert werden (U + 0061 ergibt a u + 0300 ist ein kombinierender Grabakzent). Der einzige Fehler, den ich mit quotemeta habe, ist, dass ich Dateien mit einem \n oder \r in dem von mir erstellten Pfad verwende. Ich wäre daran interessiert, andere Charaktere in nasty_names zu testen.

ShellQuote funktioniert tadellos für alle Dateinamen mit Ausnahme derer, die durch ein NUL beendet werden, wenn Erstellen einer Datei Ich habe nie einen Fehler damit gehabt.

Also was zu verwenden? Nur um es klar zu stellen: Shell-Quoting ist nicht etwas, das ich oft mache, da ich normalerweise nur Perl verwende, um eine Pipe zu einem Prozess zu öffnen. Diese Methode leidet nicht unter den besprochenen Shell-Problemen. Ich bin interessiert, seit ich gesehen habe, dass Zitat oft für die Flucht von Dateinamen verwendet wurde.

(Dank Ether habe ich IPC :: System :: Simple hinzugefügt)

Testdatei:

%Vor%     
dawg 26.09.2010, 05:24
quelle

3 Antworten

15

Quoteemeta ist unter diesen Annahmen sicher:

  1. Nur nicht-alphanumerische Zeichen haben eine besondere Bedeutung.
  2. Wenn ein nicht-alphanumerisches Zeichen eine besondere Bedeutung hat, wird es durch einen umgekehrten Schrägstrich immer unspezialisiert.
  3. Wenn ein nicht-alphanumerisches Zeichen keine besondere Bedeutung hat, wird das Setzen eines Backslashs nichts bewirken.

Die Shell verstößt gegen die Regeln 2 und 3, unabhängig davon, welchen Zitatkontext Sie verwenden - außerhalb von Anführungszeichen erzeugt Backslash-Newline keine Zeilenschaltung; In doppelten Anführungszeichen setzt Backslash-Interpunktion einen Backslash in die Ausgabe (außerhalb einer bestimmten Interpunktionsliste); und in einfachen Anführungszeichen ist alles literal und Backslash schützt Sie nicht einmal vor einem schließenden Anführungszeichen.

Ich empfehle immer noch String::ShellQuote , wenn Sie Dinge für die Shell angeben müssen. Ich empfehle auch zu vermeiden, dass die Shell Ihre Dateinamen vollständig verarbeitet, wenn Sie können, indem Sie LIST -form system / exec / open oder IPC :: Open2 , IPC :: Open3 , oder IPC :: System :: Simple .

Was Dinge außer der Shell angeht ... viele verschiedene Dinge verletzen eine oder mehrere der Regeln. Zum Beispiel haben veraltete POSIX- "Basis" -Regerexte und verschiedene Arten von Editor-Regexes Interpunktionszeichen, die standardmäßig nicht speziell sind, aber werden speziell , wenn ihnen ein Backslash vorangestellt wird. Grundsätzlich, was ich sage, ist, wissen Sie die Sache, die Sie Ihre Daten sehr gut füttern, und richtig entkommen. Verwenden Sie quotemeta nur, wenn es genau passt oder wenn Sie es für etwas verwenden, das nicht sehr wichtig ist.

    
hobbs 26.09.2010, 05:36
quelle
3

Sie können auch IPC :: System :: Simple capture() oder verwenden capturex() (was ich in einer anderen Antwort zu dieser ersten Frage vorgeschlagen habe), mit der Sie die Shell umgehen können.

Ich habe diese Zeilen zu Ihrem Skript hinzugefügt und festgestellt, dass keine Beispiele fehlgeschlagen sind:

%Vor%

Aber im Allgemeinen sollten Sie das eigentliche Problem lösen, anstatt zu versuchen, bessere Pflaster zu finden. quotemeta ist speziell dafür gedacht, Zeichen mit regulären Ausdrücken zu entkommen, die, wie Sie herausgefunden haben, keine perfekte Überlappung mit der Gruppe von Zeichen sind, die für die Shell von Bedeutung sind.

    
Ether 26.09.2010 05:34
quelle
0

Das Folgende ist eine Unix-only-Lösung; Siehe Ссылка für die Windows-Unterstützung.

Eine Alternative ist diese einfache Funktion, die auch mit Nicht-ASCII-Zeichen (unter der Annahme der richtigen Kodierung) robust arbeiten sollte, sowie \n und \r , aber ohne NUL (siehe unten).

%Vor%

Die Funktion umschließt jedes Argument in einfachen Anführungszeichen und, wenn mehrere Argumente angegeben wurden, durch Leerzeichen.

Es werden Strings in einfachen Anführungszeichen verwendet, da deren Inhalt in POSIX-ähnlichen Shells nicht interpretiert wird.

Als solches können Sie jedoch nicht einmal ' -Instanzen selbst umgehen, was die folgende Problemumgehung erfordert: Jede eingebettete ' -Instanz wird durch '\'' (sic) ersetzt, wodurch die Eingabezeichenfolge effektiv in mehrere Einzelzeichen aufgeteilt wird. In Anführungszeichen gesetzte Strings, mit escaped ' instances - \' - gespleißt in - die Shell setzt dann die Stringteile in eine einzelne Zeichenfolge zusammen.

Beispiel:

%Vor%

erzeugt ( einschließlich die umschließenden Anführungszeichen) 'I'\''m here & wëll' , die für die Shell 3 zusammenhängende Zeichenfolgen sind - 'I' , \' und '&well' , die dann zu einer einzelnen Zeichenkette zusammengefügt werden, die nach dem Entfernen des Zitats I'm here & wëll liefert.

OSX-Unicode-Einschränkung : Das HFS + speichert Dateinamen in NFD ( zerlegt Unicode-Normalform - Basisbuchstabe gefolgt von einem anderen Zeichen, das das zugehörige Diakritikum ist), während Perl normalerweise erstellt NFC ( komponierte Unicode-Normalform - ein einzelnes Zeichen identifiziert den Buchstaben mit Akzent).

Wenn Sie literale Dateinamen verwenden, spielt diese Unterscheidung keine Rolle (die Systemaufrufe machen das Mapping), aber wenn Sie Globs verwenden, tut es dies, und Sie müssen leider selbst übersetzen die zwei Formen.

Unterstützung für NUL (0x0) Zeichen.:

Ich denke nicht NUL chars. in Dateinamen sind ein echtes Anliegen:

  • Die meisten POSIX-ähnlichen Shells ( bash , dash , ksh ) ignorieren NUL chars. auf der Befehlszeile - zsh ist die einzige Ausnahme.
  • Auch wenn das laut Wikipedia kein Problem war, tun die meisten Unix-Systeme nicht Unterstützung NUL Zeichen. in Dateinamen.

Außerdem wird versucht, ein Literal mit NUL an Perls system() function zu übergeben, wodurch der Aufruf möglicherweise abgebrochen wird, weil die an sh -c übergebene Zeichenfolge abgeschnitten am ersten NUL :

%Vor%     
mklement0 25.08.2015 18:30
quelle

Tags und Links