Nur eine zusätzliche Anmerkung zu @ Kusalanandas guter Antwort .
echo run after_bundle
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:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
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-15Gebietsschema, 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 wie bashbehandeln es daher als Token-Trennzeichen in ihrer Syntax.
Das bedeutet , dass anstelle des Laufens echomit $'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.gb18030chinesischen Gebietsschema befinden, schreiben Sie ein Skript wie:
echo 詜 reboot
Dieses Skript wird 詜 rebootin einem Gebietsschema mit GB18030 oder GBK, 唰 rebootin einem Gebietsschema mit BIG5 oder BIG5-HKSCS, aber in einem C-Gebietsschema mit ASCII oder einem Gebietsschema mit ISO8859-15 oder UTF-8 ausgegeben, rebootda die GB18030-Codierung ausgeführt wird von 詜ist 0xd4 0x7c und 0x7c ist die Codierung von |in ASCII, so dass wir am Ende laufen:
echo �| reboot
(das , das jedoch das 0xd4-Byte darstellt, wird im Gebietsschema gerendert). Beispiel mit dem weniger schädlichen unameanstelle von reboot:
$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$
( unamewurde 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 wie zshund bashwird 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:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
Oder:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(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 ist echo(oder zumindest einige echo Implementierungen, zumindest die Unix-kompatiblen):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(Beachten Sie, dass dies \auch im ersten Argument für etwas Besonderes ist printf, 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:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(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 echoauch als Argument an das echoDienstprogramm übergeben (um zu sagen, wie es aufgerufen wurde), es ist das argv[0]und argcist 3, obwohl in den meisten Shells heutzutage echoeingebaut ist, so dass das exec()einer /bin/echoDatei 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]bis argv[argc - 1]) beginnt , da dies die sind, auf die die Befehle hauptsächlich einwirken.
² eine bemerkenswerte Ausnahme davon ist das lächerliche ja_JP.SJISGebietsschema 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.