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
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%Quoteemeta ist unter diesen Annahmen sicher:
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.
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.
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).
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:
bash
, dash
, ksh
) ignorieren NUL
chars. auf der Befehlszeile - zsh
ist die einzige Ausnahme. 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
: