Der einfachste Weg, ein fehlendes Zitat in einem Bash eines Skripts zu finden?

7

Ich habe ein Bash-Skript, das derzeit mehr als 700 Zeilen lang ist. Nach einer besonders langen Bearbeitungsrunde gibt es nun folgende Fehler:

./run_me.sh: line 693: unexpected EOF while looking for matching `''
./run_me.sh: line 702: syntax error: unexpected end of file

Es gibt jedoch nichts Falsches, was ich an Zeile 693 sehen kann. Es gibt nicht einmal ein Zitat darauf.

Ich habe versucht zu laufen bash -x run_me.shund kann sehen, dass die letzte Zeile ausgeführt wird, aber auch an dieser Zeile ist nichts auszusetzen (und der Code zwischen dieser Zeile und 693 ist praktisch der größte Teil des Codes).

Ich kann ganze Teile des Codes auskommentieren, aber dann sehe ich eher Fehler aufgrund fehlender Funktionen usw. als den EOF-Fehler, den ich erhalte.

Wie soll jemand das fehlende Zitat finden, wenn die Zeilennummer falsch gemeldet wird?

(Warum ist die Zeilennummer von bash überhaupt so weit entfernt?)

Bearbeiten

Übrigens habe ich meinen speziellen Fehler gefunden (durch Kommentieren von Schwaden), der tatsächlich }in einer variablen Erweiterung bei einer beliebigen Zeilennummer fehlte, die nicht in der Nähe der durch die Fehlermeldung angegebenen Zeile liegt - zitierbasierte Syntaxhervorhebung hat hier nicht geholfen, z die fehlende Klammer in "${MY_ARRAY[@]"(sollte sein "${MY_ARRAY[@]}").

jimbobmcgee
quelle
Sie müssen keine Schwaden kommentieren - nur den Kopf jedes zusammengesetzten Befehls (oder jeder Funktionsdefinition) . Kommentieren Sie dann jedes einzeln ab dem Kopf der Datei aus. Dann mach einfach so sh -nv <scriptwie du. Sobald sich Ihre Fehlermeldung ändert, haben Sie den zusammengesetzten Befehl gefunden, in dem Ihr Problem liegt. Und die Zeilennummern sind in Ordnung - jede Funktion bekommt ihre eigene.
Mikeserv
@mikeserv - kannst du erweitern auf "Die Zeilennummern sind in Ordnung - jede Funktion bekommt ihre eigene" ? Es gibt sicherlich keine Funktionen, die 693 Zeilen lang sind (es sei denn, Sie zählen das Skript selbst als Funktion). Wenn der Fehler nicht an oder zwischen den beiden gemeldeten Zeilen liegt, scheint mir das nicht in Ordnung zu sein. Wenn es eine Methode gibt, um die tatsächlich fehlerhafte Zeile (oder sogar den Beginn des fehlgeschlagenen zusammengesetzten Befehls) aus den von bash gemeldeten Zeilennummern abzuleiten / zu erraten, wäre dies möglicherweise ein guter Anfang.
jimbobmcgee
Ok, Sie machen gute Punkte, aber wenn Sie dieses -nvDing ausprobiert haben, bekommen Sie vielleicht eine bessere Idee - die Eingabeaufforderungen werden Sie darauf $PS2hinweisen . Sie werden es bekommen, wenn die Shell irgendwann begonnen hat, ein Zitat oder eine zusammengesetzte Ebene zu interpretieren und es nicht geschafft hat Schließen Sie dieses Token, seit die letzte Zeile in der Eingabe aufgetreten ist. Versuchen Sie auch: PS4='LAST EXECLINE: $((LAST+!(LAST=LINENO)))'; set -xweil die Leinen in Unterschalen manchmal ziemlich lustig werden können.
Mikeserv
Wie sich herausstellt, habe ich zumindest einige davon schon etwas besser erklärt .
Mikeserv

Antworten:

7

Ein Low-Tech-Ansatz ist

tr -cd "'\n" < run_me.sh | awk 'length%2==1 {print NR, $0}'

Das trlöscht alle Zeichen mit Ausnahme von einfachen Anführungszeichen und Zeilenumbrüchen und awkidentifiziert die Zeilen mit einer ungeraden Anzahl von Zeichen (dh nicht übereinstimmenden Anführungszeichen). Überprüfen Sie sie einzeln; Beachten Sie, dass gültige Zeichenfolgen wie gekennzeichnet "That's not a bug!"werden. Wenn das Problem dadurch nicht hervorgehoben wird, versuchen Sie es erneut mit '"\n' (um nicht übereinstimmende doppelte Anführungszeichen zu finden). Als nächstes erweitert das trzu ermöglichen (), {}und schließlich {} durch zu gehen. Zu diesem Zeitpunkt wird die manuelle Überprüfung der Ausgabe zu einer weniger fruchtbaren Angelegenheit. Während (und )normalerweise innerhalb derselben Zeile übereinstimmen und Anführungszeichen und eckige Klammern fast immer vorhanden sind, gilt dies nicht für {und }.

Wenn Sie das Problem auf eine nicht übereinstimmende geschweifte Klammer eingegrenzt haben und insbesondere wenn Sie einen Bereich in der Datei eingegrenzt haben, fahren Sie mit Plan B fort. Öffnen Sie die Datei in vim(oder vi). Gehen Sie zu einem {Zeichen, von dem Sie glauben, dass es vor dem Fehler steht, und geben Sie es ein %. Wenn der Cursor zu dem springt, von dem } Sie glauben, dass er mit dem übereinstimmt, mit dem {Sie begonnen haben, fahren Sie mit dem nächsten fort {und wiederholen Sie den Vorgang. Wenn zu einem }Wert gesprungen wird, der nicht mit dem übereinstimmt, mit dem {Sie begonnen haben, tritt der Fehler zwischen diesen beiden geschweiften Klammern auf. Wenn es nicht verschoben wird, tritt der Fehler zwischen Ihrem aktuellen Speicherort und dem Ende der Datei auf. Hineinzoomen.

Dieser Ansatz eignet sich möglicherweise etwas besser für Programmdateien in Sprachen wie C, C ++ und Java (wenn ihre Compiler nicht gut genug arbeiten), sollte jedoch für Shell-Skripte recht gut funktionieren.

G-Man sagt "Reinstate Monica"
quelle
Vielen Dank! Manchmal ist Low-Tech besser als No-Tech! änderte das 'in ein \ "und fand mein fehlendes doppeltes Anführungszeichen in Sekunden.
Mike
5

Einfachster Weg? Verwenden Sie einen Editor mit Syntaxfarbe, der die von Ihnen verwendete Shell kennt, und überprüfen Sie sie visuell. Wenn Sie einen großen Streifen String-Farbe erhalten, wissen Sie, dass Sie ein Zitat ausgelassen haben. Fast jeder anständige Programmiereditor hat Syntaxfarben.

Syntaxfärbung macht es manchmal falsch, aber das ist normalerweise ein Zeichen dafür, dass Ihr Programm zu komplex ist und Menschen es wahrscheinlich auch falsch machen.

Für Shell - Programmierung, stellen Sie sicher , eine Schriftart zu verwenden , wo ", 'und `sind leicht auseinander zu halten . Stellen Sie sicher, dass Sie nicht versehentlich Nicht-ASCII-Zeichen verwendet haben, die wie ASCII-Anführungszeichen aussehen, z ‘’“”.

Gilles 'SO - hör auf böse zu sein'
quelle
Die EOF schlägt ein fehlendes Backquote vor. Im Falle eines fehlenden Zitats meldet bash eine "nicht abgeschlossene Zeichenfolge in Anführungszeichen".
Emmanuel
War tatsächlich ein }Mangel in einer zitierten Zeichenfolge, die Geanys Kolorierung nicht entdeckte.
jimbobmcgee
@ jimbobmcgee Ah. Emacs erkennt das nicht, Vim jedoch.
Gilles 'SO - hör auf böse zu sein'
Ja vimmacht einen vernünftigen Job ... irgendwann. Zuerst mußte es nicht mehr ignorieren :syntax ondurch die Installation vim-enhancedüber vim-minimal(dank Fedora!), Dann hatte sie in ein anständiges Farbschema zu zwingen, da dunkelblau war tatsächlich sichtbar (dank LXTerminal!). Danach, vimtat Highlight Klammern mit einem schönen roten Hintergrund fehlt!
jimbobmcgee
Manchmal kann es schwierig sein, das zu tun. Ich habe jetzt ein Array mit über 2000 Werten, das in Sublime Text weiß erscheint, wobei alle meine anderen Arrays gelb sind. Ich würde sehr lange aufpassen und seitwärts scrollen müssen.
DisplayName
5

Ein externes Flusen-Tool wie ShellCheck kann Probleme erkennen und hat möglicherweise bessere Nachrichten und Standorte als sich bashselbst.

Bei einem Programm, bei dem es sich hauptsächlich um echoAnweisungen mit einem "${MY_ARRAY[1]"in der Mitte handelt, weist ShellCheck darauf hin, dass die angegebene Zeichenfolge nicht analysiert werden konnte. Es führt das Problem sogar auf das $Zeichen zurück und weist darauf hin, dass die Parametererweiterung fehlerhaft war.

ShellCheck funktioniert unter anderem mit Vim, Emacs, SublimeText und Atom.

RJHunter
quelle
1

Mit der Low-Tech-Lösung von G-Man konnte ich ein großes Problem lösen, das ich in einem Bash-Skript mit mehr als 2000 Zeilen hatte.

Ich würde nur die folgende Zeile hinzufügen, die für eine ungerade Anzahl von Doppelzitaten dasselbe tut wie die Antwort von G-Man für Einzelzitate.

tr -cd "\"\n" < my_script.sh | awk 'length%2==1 {print NR, $0}'

Übrigens ist shellcheck.net sehr nett und jedes gute Skript sollte es durchgehen.

Orsiris de Jong
quelle