Ich habe einige ähnliche Themen gesehen, aber sie beziehen sich darauf, keine Variablen zu zitieren, von denen ich weiß, dass sie zu unerwünschten Ergebnissen führen können.
Ich habe diesen Code gesehen und mich gefragt, ob es möglich ist, etwas einzufügen, das ausgeführt werden soll, wenn diese Codezeile ausgeführt wird:
echo run after_bundle
Antworten:
Für den speziellen Fall
Zitate sind nicht erforderlich. Es ist kein Anführungszeichen erforderlich, da das Argument
echo
statische Zeichenfolgen sind, die keine Variablenerweiterungen oder Befehlsersetzungen usw. enthalten. Es handelt sich um "nur zwei Wörter" (und wie Stéphane betont , werden sie zusätzlich aus dem tragbaren Zeichensatz erstellt ).Die "Gefahr" entsteht, wenn Sie mit variablen Daten arbeiten, die die Shell erweitern oder interpretieren kann. In solchen Fällen muss darauf geachtet werden, dass die Shell das Richtige tut und das Ergebnis dem entspricht, was beabsichtigt ist.
Die folgenden zwei Fragen enthalten relevante Informationen dazu:
echo
wird manchmal verwendet, um potenziell schädliche Befehle in Antworten auf dieser Site zu "schützen". Zum Beispiel kann ich zeigen, wie Dateien mit entfernt oder an ein neues Ziel verschoben werdenoder
Dies würde Befehle auf dem Terminal ausgeben, anstatt Dateien tatsächlich zu entfernen oder umzubenennen. Der Benutzer kann dann die Befehle überprüfen, entscheiden, dass sie in Ordnung aussehen, sie entfernen
echo
und erneut ausführen.Ihr Befehl
echo run after_bundle
kann eine Anweisung an den Benutzer sein, oder es kann sich um einen "auskommentierten" Code handeln, der zu gefährlich ist, um ausgeführt zu werden, ohne die Konsequenzen zu kennen.Mit
echo
wie dieser, muss man wissen , was die modifizierte Befehl tut und man muss sicherstellen , dass der modifizierte Befehl tatsächlich ist sicher (es wäre möglicherweise nicht , wenn es Umleitungen enthalten ist , und es auf einer Pipeline mit nicht funktioniert, etc.)quelle
echo rm "first file.txt" "second file.txt"
in irgendeiner Weise anders istecho rm "first" "file.txt" "second" "file.txt"
, da die Ausgabe von beiden gleich ist. Wenn Sie einen Shell-Befehl als Ausgabe generieren möchten, müssen Sie einenprintf '%q ' rm "first file.txt" "second file.txt"; echo
oder einen entsprechenden Befehl verwenden , der syntaktische Anführungszeichen neu generiert, die als übergeben ausgewertet werdenargv
.sh
ist kein ungewöhnliches Muster. Die Leute fragen: "Warum funktioniert dasfoo
, wenn ich es in einer Befehlszeile ausführe, aber dieses Skript, das genau diese Zeichenfolge mitecho
vor der Zeile ausgibt, tut dies nicht." "" passiert die ganze Zeit hier. Das Debuggen der Ausgabe ist nicht hilfreich, wenn es Ihre Fehler verbirgt - und wenn Ihre Fehler mit dem Zitieren zusammenhängen,echo
werden sie nicht angezeigt.Nur eine zusätzliche Anmerkung zu @ Kusalanandas guter Antwort .
ist in Ordnung, da keines der Zeichen in diesen 3 Argumenten¹ an übergeben wurde
echo
Zeichen enthält, die für die Shell speziell sind.Und (der zusätzliche Punkt, den ich hier ansprechen möchte) es gibt kein Systemgebietsschema, in dem diese Bytes in Zeichen übersetzt werden könnten, die für die Shell speziell sind.
Alle diese Zeichen befinden sich in dem, was POSIX als tragbaren Zeichensatz bezeichnet . Diese Zeichen sollten in allen Zeichensätzen auf einem POSIX-System² vorhanden und gleich codiert sein.
Diese Befehlszeile wird also unabhängig vom Gebietsschema gleich interpretiert.
Wenn wir jetzt Zeichen außerhalb dieses tragbaren Zeichensatzes verwenden, ist es eine gute Idee, sie in Anführungszeichen zu setzen, auch wenn sie nicht speziell für die Shell sind, da in einem anderen Gebietsschema die Bytes, aus denen sie bestehen, möglicherweise als unterschiedliche Zeichen interpretiert werden speziell für die Shell. Beachten Sie
echo
, dass das Problem nicht bei einem Befehl oder einem anderen Befehl liegtecho
sondern darin, wie die Shell ihren Code analysiert.Zum Beispiel in einem UTF-8:
Das
à
ist als 0xc3 0xa0 codiert. Wenn Sie diese Codezeile in einem Shell-Skript haben und das Shell-Skript von einem Benutzer aufgerufen wird, der ein Gebietsschema verwendet, dessen Zeichensatz nicht UTF-8 ist, können diese beiden Bytes sehr unterschiedliche Zeichen enthalten.In einem
fr_FR.ISO8859-15
Gebietsschema, einem typischen französischen Gebietsschema, das den Standard-Einzelbyte-Zeichensatz verwendet, der die französische Sprache abdeckt (dasselbe gilt für die meisten westeuropäischen Sprachen einschließlich Englisch), wird dieses 0xc3-Byte als das interpretiertÃ
Zeichen und 0xa0 als Nicht- Breaking Space Charakter.Und auf einigen Systemen wie NetBSD³ wird dieses nicht unterbrechende Leerzeichen als leeres Zeichen betrachtet (
isblank()
auf dem true zurückgegeben wird, mit dem es übereinstimmt[[:blank:]]
), und Shells wiebash
behandeln es daher als Token-Trennzeichen in ihrer Syntax.Das bedeutet , dass anstelle des Laufens
echo
mit$'voil\xc3\xa0'
als Argument, laufen sie es mit$'voil\xc3'
als Argument, was bedeutet , es nicht gedruckt wird ,voilà
korrekt.Es wird noch viel schlimmer mit chinesischen Zeichensätzen wie BIG5, BIG5-HKSCS, GB18030, GBK , die viele Zeichen , deren Codierung enthält die gleiche Codierung wie die haben
|
,`
,\
(zu nennen das Schlimmste) (auch , dass lächerliche SJIS, auch bekannt als Microsoft Kanji, mit Ausnahme dass es¥
statt\
, aber immer noch als behandelt wird\
von den meisten Tools wird, da es dort als 0x5c codiert ist).Wenn Sie sich beispielsweise in einem
zh_CN.gb18030
chinesischen Gebietsschema befinden, schreiben Sie ein Skript wie:Dieses Skript wird
詜 reboot
in einem Gebietsschema mit GB18030 oder GBK,唰 reboot
in einem Gebietsschema mit BIG5 oder BIG5-HKSCS, aber in einem C-Gebietsschema mit ASCII oder einem Gebietsschema mit ISO8859-15 oder UTF-8 ausgegeben,reboot
da die GB18030-Codierung ausgeführt wird von詜
ist 0xd4 0x7c und 0x7c ist die Codierung von|
in ASCII, so dass wir am Ende laufen:(das , das jedoch das 0xd4-Byte darstellt, wird im Gebietsschema gerendert). Beispiel mit dem weniger schädlichen
uname
anstelle vonreboot
:(
uname
wurde ausgeführt).Mein Rat wäre also, alle Zeichenfolgen zu zitieren, die Zeichen außerhalb des tragbaren Zeichensatzes enthalten.
Beachten Sie jedoch, dass es besser ist, nicht oder oder (innerhalb dessen und / oder immer noch speziell) zu verwenden, sondern stattdessen Zeichen außerhalb des tragbaren Zeichensatzes zu zitieren , da die Codierung von
\
und`
in der Codierung einiger dieser Zeichen enthalten ist.\
"..."
$'...'
`
\
'...'
Ich bin mir nicht bewusst jedes System , das eine locale hat , wo die charset jedes Zeichen hat (außer
'
sich selbst natürlich) , dessen Codierung enthält die Kodierung'
, so dass diejenigen , auf'...'
jeden Fall die sicherste sein sollte.Beachten Sie, dass mehrere Shells auch eine
$'\uXXXX'
Notation unterstützen, um Zeichen basierend auf ihrem Unicode-Codepunkt auszudrücken. In Shells wiezsh
undbash
wird das Zeichen codiert in den Zeichensatz des Gebietsschemas eingefügt (kann jedoch zu unerwartetem Verhalten führen, wenn dieser Zeichensatz dieses Zeichen nicht enthält). Auf diese Weise können Sie vermeiden, Nicht-ASCII-Zeichen in Ihren Shell-Code einzufügen.Also oben:
Oder:
(Mit der Einschränkung könnte das Skript beschädigt werden, wenn es in Gebietsschemas ausgeführt wird, in denen diese Zeichen nicht vorhanden sind.)
Oder besser, da dies
\
auch etwas Besonderes istecho
(oder zumindest einigeecho
Implementierungen, zumindest die Unix-kompatiblen):(Beachten Sie, dass dies
\
auch im ersten Argument für etwas Besonderes istprintf
, sodass Nicht-ASCII-Zeichen dort auch besser vermieden werden, falls sie die Codierung von enthalten können\
.)Beachten Sie, dass Sie auch Folgendes tun können:
(Das wäre übertrieben, könnte Ihnen aber Sicherheit geben, wenn Sie nicht sicher sind, welche Zeichen im tragbaren Zeichensatz enthalten sind.)
Stellen Sie außerdem sicher, dass Sie niemals die alte
`...`
Form der Befehlssubstitution verwenden (die eine andere Ebene der Backslash-Verarbeitung einführt), sondern$(...)
stattdessen verwenden.¹ wird technisch
echo
auch als Argument an dasecho
Dienstprogramm übergeben (um zu sagen, wie es aufgerufen wurde), es ist dasargv[0]
undargc
ist 3, obwohl in den meisten Shells heutzutageecho
eingebaut ist, so dass dasexec()
einer/bin/echo
Datei mit einer Liste von 3 Argumenten durch das simuliert wird Schale. Es ist auch üblich, die Liste der Argumente so zu betrachten, dass sie mit dem zweiten (argv[1]
bisargv[argc - 1]
) beginnt , da dies die sind, auf die die Befehle hauptsächlich einwirken.² eine bemerkenswerte Ausnahme davon ist das lächerliche
ja_JP.SJIS
Gebietsschema von FreeBSD-Systemen, deren Zeichensatz weder\
noch~
Charakter hat!³ Beachten Sie, dass viele Systeme (FreeBSD, Solaris, jedoch keine GNU-Systeme) U + 00A0 als
[[:blank:]]
in UTF-8-Gebietsschemas betrachten, aber nur wenige in anderen Gebietsschemas wie denen, die ISO8859-15 verwenden, möglicherweise, um diese Art von Problem zu vermeiden.quelle
echo
... übergeben wurden", ich zähle nur 2 Argumente, die an den Befehl übergeben werdenecho
, die Argumente, die ich zählen kann, sindrun
undafter_bundle
erklären, wie Sie gezählt und zu 3 Argumenten gekommen?echo
).(exec -a foo /bin/echo --help)
Informationen zum Übergeben eines beliebigen ersten Arguments an das/bin/echo
Dienstprogramm finden Sie auf einem GNU-System und mit der GNU-Shell .$0
und Positionsparameter in Schalen.iconv
in dieESC
konvertiert wird'
. Versuchen Sie (als Beispiel):printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
'
. Versuchen Sie esprintf '\u2804' | iconv -f utf8 -t BRF | xxd
. Es gibt Codierungen, in denen viele Codepunkte entstehen'
. Rund 8695 Codepunkte in UCS-4 werden'
. Versuchen Sie esprintf '\U627' | iconv -cf utf-8 -t UCS-4
. Mehrere (37) Codierungen konvertieren das Zeichen 0x127 in a'
. Versuchen Sieprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd