Wie kann ich die wörtlichen Zeichen einer Bash-Befehlszeichenfolge überprüfen?

15

Ich hatte dieses seltsame Verhalten heute Morgen in einem Bash-Terminal:

user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
bash: [: missing «]»
user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
true
  • Der erste Befehl war geklebt aus einem mit gedit bearbeiteten Skript.
  • Der zweite war direkt eingegeben im terminal.

Nach einigem Graben finde ich das heraus Entfernen des 30. Zeichens (Das Leerzeichen zwischen client.conf und "]") und das Ersetzen durch ein Leerzeichen haben dazu geführt, dass der Befehl wieder funktioniert.

Meine Annahme war richtig: Ein unbekanntes Leerzeichen ist in den Befehl eingedrungen , aber die Frage ist:

  1. Wie kann ich diese Zeichen im Terminal anzeigen, damit ich den Befehl debuggen kann? Und noch wichtiger:
  2. Wie kann ich das verhindern?

Übrigens, ich verwende Ubuntu 18.04 / Französisch. Das Skript, von dem ich den Befehl einfüge, befindet sich auf einem USB-Laufwerk und wurde möglicherweise auch unter Windows bearbeitet.


Vielen Dank für Ihre sehr guten Antworten. Der schlechte Charakter ist a c2 a0 Nicht unterbrechendes Leerzeichen UTF-8-Zeichen. Die Frage Wie entferne ich einen speziellen 'M-BM-' Charakter mit sed hat interessante Fakten über diesen Charakter.

Das Seltsame ist, dass das Skript frei von diesem Charakter ist. Ich weiß also nicht, woher es kam.

Gabriel Glenn
quelle
3
Verwenden Sie einen Editor, der solche Zeichen hervorhebt. Syntaxhervorhebung hilft auch sehr. Niemals direkt aus dem Internet in das Terminal einfügen, sondern immer den oben genannten Editor durchlaufen.
choroba
2
Möglicherweise möchten Sie den Problembefehl in Ihrer Verlaufsliste suchen und dann die Ausgabe durch ein Hex-Anzeigeprogramm leiten. Damit Sie nicht durch eine lange Liste waten müssen, führen Sie entweder den Befehl erneut aus, um ihn am Ende der Verlaufsliste zu platzieren, und führen Sie ihn aus history 2|xxd (weil der history Befehl selbst ist immer der letzte in der Liste) oder Typ history|grep "CommandWithProblem"|xxd. Sie können anstelle von ein beliebiges anderes Hex-Anzeigeprogramm verwenden xxd, aber das ist ein Standardformat, das ich mag.
AFH
@ Gabriel Glenn, bitte markieren Sie die beste / hilfreichste / welche Antwort auch immer als " akzeptiert "mit dem tick - anstatt zu jedem zu kommentieren, dass die antwort geholfen hat. Info
Attie
1
@Attie, ja, normalerweise warte ich 24 Stunden, bevor ich die besten Antworten akzeptiere, wie in: meta.stackexchange.com/questions/5234/…
Gabriel Glenn
1
Persönlich würde ich verwenden set -x. Dies zeigt Ihnen den Befehl & amp; wie es aufgeteilt ist. Es würde nicht unbedingt "schlechter Charakter hier" heißen, aber es würde Ihnen zeigen, dass sich Bash nicht auf diesen Charakter aufteilt.
Patrick

Antworten:

11

Eine Möglichkeit besteht darin, sich die Zeichen anzusehen, die Sie mit einem Hex-Viewer oder Editor verwenden möchten. hexdump ist eine gute Option, wenn Sie auf das Terminal beschränkt sind.

$ hexdump -Cv <<"EOF"
> [ -f /etc/openvpn/client.conf ] && echo true
> EOF
00000000  5b 20 2d 66 20 2f 65 74  63 2f 6f 70 65 6e 76 70  |[ -f /etc/openvp|
00000010  6e 2f 63 6c 69 65 6e 74  2e 63 6f 6e 66 20 5d 20  |n/client.conf ] |
00000020  26 26 20 65 63 68 6f 20  74 72 75 65 0a           |&& echo true.|
0000002d

Sie können hier sehen, dass die space, close-square-brace, space sind richtig - 0x20, 0x5D, 0x20.

Diese Werte sind ASCII-Codes, angezeigt in hexadezimal . Beliebiger Wert außerhalb des Bereichs 0x20 - 0x7E ist kein " druckbares Zeichen " Was ASCII anbelangt, wird es mit Befehlszeilenschnittstellen höchstwahrscheinlich nicht funktionieren.

Hinweis: Ich habe dein erstes kopiert " gebrochen "Linie zur Verwendung in der hexdump Beispiel oben, so hat etwas das ersetzt Nicht-ein-ASCII-Raum mit einem ASCII-Leerzeichen zwischen Ihrer ursprünglichen Quelle und Ihrer gerenderten Frage.


Führen Sie die folgenden Schritte aus, um dies zu wiederholen:

  1. Art hexdump -Cv <<"EOF" und drücke Eingeben
  2. Fügen Sie den gewünschten Text ein
  3. Art EOF in einer eigenen Zeile und drücken Sie Eingeben

Terminals und Befehlszeilenschnittstellen können Sonderzeichen nicht gut verarbeiten, wie Sie festgestellt haben. Wenn Sie beim Formatieren von Dokumenten nicht sehr vorsichtig sind, treten auch Probleme mit Microsoft Word (und anderen) auf, wenn Sie " intelligente Anführungszeichen ", Gedankenstriche, die Liste geht weiter ...

Finde den Unterschied: (die Spitze ist " intelligente Anführungszeichen ", der Boden ist" gerade Anführungszeichen ")

example of smart quotes vs straight quotes

$ hexdump -Cv <<"EOF"
> “quoted string”
> EOF
00000000  e2 80 9c 71 75 6f 74 65  64 20 73 74 72 69 6e 67  |...quoted string|
00000010  e2 80 9d 0a                                       |....|
00000014

Hier sind die offenen Anführungszeichen keine einfachen ASCII-Anführungszeichen ( " ), sind aber ein Unicode / UTF-8 Serie - 0xE2, 0x80, 0x9C, oder U+201C - was das Terminal nicht erwartungsgemäß handhabt.

Kiwys Vorschlag von cat -A erledigt auch die Arbeit:

$ cat -A <<"EOF"
> “quoted string”
> EOF
M-bM-^@M-^\quoted stringM-bM-^@M-^]$

Hinweis: beim Benutzen echo "..." | hdSie haben die Chance, dass die Bash Teile der Zeichenfolge ersetzt, die Sie untersuchen möchten. Dies ist besonders wichtig, wenn Sie versuchen, Komponenten eines Skripts zu überprüfen.

Versuchen Sie zum Beispiel:

$ echo "${USER}"
attie

$ echo "`whoami`"
attie

$ echo "$(whoami)"
attie

$ cat <<EOF
> ${USER}
> EOF
attie

Diese Methoden ersetzen Komponenten durch den entsprechenden Text. Verwenden Sie eine der folgenden Methoden, um dies zu vermeiden. Beachten Sie die Verwendung von einfachen Anführungszeichen ( ' ), und ein " zitiert Heredoc " ( "EOF" ).

$ echo '${USER}'
${USER}

$ echo '`whoami`'
`whoami`

$ echo '$(whoami)'
$(whoami)

$ cat <<"EOF"
> ${USER}
> EOF
${USER}
Attie
quelle
Diese Lösung funktioniert: echo "[ -f /etc/openvpn.ovpn ]" | hd kehrt zurück [...] c2 a0 [...]. Wir können das sehen c2 a0 UT-8-Zeichen nicht brechender Raum
Gabriel Glenn
18

Du könntest benutzen cat mit dem -A Option: aus dem Handbuch:

   -A, --show-all
          equivalent to -vET
   -E, --show-ends
          display $ at end of each line
   -T, --show-tabs
          display TAB characters as ^I
   -v, --show-nonprinting
          use ^ and M- notation, except for LFD and TAB

So cat -A yourscrip.sh zeigt dir unsichtbare und seltsame Charaktere.

Kiwy
quelle
7
Diese Lösung funktioniert: echo "[ -f /etc/openvpn.ovpn ]" | cat -A kehrt zurück [ -f /etc/openvpn/client.ovpnM-BM- ]$. Wir können das sehen M-BM- UT-8-Zeichen nicht brechender Raum
Gabriel Glenn
@ GabrielGlenn froh, dass dir das geholfen hat.
Kiwy
9

echo "<your command>" | hd sollte arbeiten. Suchen Sie nach einem Backspace (0x08) oder Zeichen mit den Codes & gt; = 80. echo "<your command>" | wc -b Es ist auch eine gute Idee, zu überprüfen, ob die Anzahl mit den angezeigten Werten übereinstimmt.

Das Kopieren von Inhalten aus Dateien, die mit "Office" im Namen erstellt wurden, ist gefährlich, da solche Software häufig das Ersetzen von Zeichen erlaubt: Achten Sie auf doppelte Anführungszeichen in Französisch, die durch "Guillemets" ersetzt werden, und auf einfache Anführungszeichen in Englisch Äquivalente öffnen / schließen. Das härteste, das ich jemals gefunden habe, war ein nicht unterbrechendes Leerzeichen mit einer Breite von 0 in der Mitte eines Dateinamens (3 Tage Ausfallzeit des Servers ...).

xenoid
quelle
2
Es ist erwähnenswert hd ist die Abkürzung für hexdump was auch in Atties Antwort erwähnt wird.
Mikael Kjær
@ MikaelKjær - Auf Ubuntu, hd ist äquivalent zu hexdump -C.
AFH
1
@xenoid: Ich sagte "bearbeitet unter Windows", nicht mit einem Office Writer bearbeitet, wir sind nicht verrückt;). Wenn es bearbeitet wurde, war es mit Notepad ++.
Gabriel Glenn
1
Diese Lösung funktioniert: echo "[ -f /etc/openvpn.ovpn ]" | hd kehrt zurück [...] c2 a0 [...]. Wir können das sehen c2 a0 UT-8-Zeichen nicht brechender Raum
Gabriel Glenn
2

Bash und andere Shells wie zsh können die aktuelle Befehlszeile in einem Editor öffnen. Die Standardverknüpfung für Bash ist C-x C-e ( Strg X Strg E ), und es öffnet sich in der ersten verfügbaren von $VISUAL, $EDITOR und Emacs. In der Praxis ist dies für das Debuggen und Ändern komplexer Befehle von unschätzbarem Wert. Je nachdem, wie Sie es sehen, ist zsh hier freundlicher als bash: Wenn der Editor beendet wird, führt bash den Befehl sofort aus, während zsh darauf wartet, dass Sie drücken Eingeben (Damit haben Sie mehr Möglichkeiten, den Befehl zu bearbeiten.)

Nach dem Öffnen des Befehls in einem Editor können Sie die Editoren so konfigurieren, dass Nicht-ASCII-Zeichen anders angezeigt werden.

Zum Beispiel, mit Vim Mit diesen Einstellungen:

set encoding=latin1
set isprint=
set display+=uhex

enter image description here

Oder passen Sie die Methoden der anderen Antworten an:

bash-4.4$ f() { cat -A "$@"; false; }   # exit false to prevent bash from running the command
bash-4.4$ VISUAL=f
bash-4.4$ [ -f /etc/openvpn/client.conf ] && echo true  # C-x C-e here
[ -f /etc/openvpn/client.confM-BM- ] && echo true$
muru
quelle