Ich habe eine Bash-Logging-Bibliothek geschrieben, um mit einigen komplexen Skripten implementiert werden, die meine Firma derzeit verwendet. Ich war todadset auf den Skript-Dateinamen ($ {BASH_SOURCE}) und die Zeilennummer ($ {LINENO}) des aufrufenden Skripts bei den Protokollaufrufen. Ich wollte mich jedoch nicht auf den Benutzer oder das Implementierungsscript verlassen müssen, um diese beiden Variablen als Parameter zu übergeben. Wenn dies C/C++ wäre, würde ich einfach ein Makro erstellen, das "__FILE__" und "__LINE__" der Parameterliste vorstellt.Bash-Parameter-Anführungszeichen und Eval
Ich konnte endlich diesen Teil arbeiten. Hier sind einige viel vereinfachte Abstracts als Proof of Concept:
Hier ist die Logging-Bibliothek:
# log.sh
LOG="eval _log \${BASH_SOURCE} \${LINENO}"
_log() {
_BASH_SOURCE=`basename "${1}"` && shift
_LINENO=${1} && shift
echo "(${_BASH_SOURCE}:${_LINENO}) [email protected]"
}
Und eine Implementierung Testskript:
# MyTest.sh
. ./log.sh
${LOG} "This is a log message"
# (test.sh:5) This is a log message
Das funktioniert ziemlich gut (und ich war begeistert, dass es zuerst funktioniert). Dies hat jedoch ein eklatantes Problem: Die Interaktion zwischen Anführungszeichen und eval. Wenn ich den Anruf mache:
${LOG} "I'm thrilled that I got this working"
# ./test.sh: eval: line 5: unexected EOF while looking for matching `''
# ./test.sh: eval: line 6: syntax error: unexpected end of file
Jetzt glaube ich, dass ich verstehe, warum das passiert. Die in Anführungszeichen gesetzten Parameter bleiben intakt, wenn sie an eval übergeben werden. Zu diesem Zeitpunkt wird der Inhalt unverändert in die resultierende Befehlszeichenfolge eingefügt. Ich weiß, dass ich das beheben kann, indem ich etwas entfliehe; aber ich WIRKLICH wollen nicht die Implementierungsskripts zu zwingen, dies zu tun haben. Bevor ich diese "eval macro" -Funktionalität implementiert habe, ließ ich Benutzer direkt zu "_log" aufrufen und erlaubte ihnen, optional "$ {LINENO}" zu übergeben. Mit dieser Implementierung funktionierte der obige fehlgeschlagene Aufruf (mit nur einem Satz in Anführungszeichen) einwandfrei.
Auf der untersten Ebene, alles, was ich wirklich will, ist für einen Skript in der Lage sein aufrufe [Funktion/Makro lügt] „String mit speziellem characers anmelden“ und die resultierenden Protokollmeldung enthalten hat die Dateinamen und Zeile Nummer des aufrufenden Skripts, gefolgt von der Protokollnachricht. Wenn es möglich ist, würde ich annehmen, dass ich sehr nahe bin, aber wenn etwas, das ich übersehe, etwas anderes erfordert, bin ich auch dafür offen. Ich kann die Benutzer nicht zwingen, allen ihren Nachrichten zu entkommen, da dies wahrscheinlich dazu führen wird, dass sie diese Bibliothek nicht benutzen. Das ist solch ein Problem, dass, wenn ich keine Lösung dafür finden kann, ich wahrscheinlich zu der alten Fähigkeit zurückkehren werde (die $ {LINENO} erforderte, um als Funktionsparameter übergeben zu werden - das war viel weniger aufdringlich).
TLDR: Gibt es eine Möglichkeit, eval dazu zu bringen, Sonderzeichen innerhalb eines in Anführungszeichen gesetzten Parameters zu respektieren, ohne ihnen entkommen zu müssen?
Wenn Sie Bash-spezifische Konstrukte verwenden, sollte Ihr Logging-Skript nicht "log.sh" heißen. Es sollte "log.bash" sein. –
@WilliamPursell - Ich habe ein wenig gesucht und konnte keinen Standard bezüglich der Namenskonventionen von Shell-Skripten finden. Tatsächlich scheinen die meisten Leute ein Suffix ganz zu verlassen. Um ehrlich zu sein habe ich noch nie etwas anderes als '\ *. Sh' (oder ein Skript ohne Erweiterung/Suffix) gesehen. Und praktisch sollte es keine Auswirkungen haben, oder? Der Interpreter wird entweder aus der ersten Zeile des Skripts gezogen oder die aktuelle Shell wird verwendet. Es scheint, dass es im Wesentlichen nur auf persönliche Vorlieben ankommt. Aber vielleicht kann "\ *. Sh" für einen Benutzer bedeuten, dass das Skript "sh" verwendet. – LousyG
Die einzige praktische Auswirkung wäre, wenn ein Entwickler Ihre Funktionen mit einer anderen Shell verwendet. Mit einem * .sh-Namen würde ein Entwickler vernünftigerweise annehmen, dass Ihre Bibliothek in einem Zsh-Skript bezogen werden kann. –