Ich versuche, einen Trockenlaufmechanismus für mein Skript zu implementieren, und stelle mich dem Problem, dass Anführungszeichen entfernt werden, wenn ein Befehl als Argument an eine Funktion übergeben wird und zu unerwartetem Verhalten führt.
dry_run () {
echo "$@"
#printf '%q ' "$@"
if [ "$DRY_RUN" ]; then
return 0
fi
"$@"
}
email_admin() {
echo " Emailing admin"
dry_run su - $target_username -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
echo " Emailed"
}
Ausgabe ist:
su - webuser1 -c cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com
Erwartet:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' [email protected]"
Wenn printf anstelle von echo aktiviert ist:
su - webuser1 -c cd\ /home/webuser1/public_html\ \&\&\ git\ log\ -1\ -p\|mail\ -s\ \'Git\ deployment\ on\ webuser1\'\ user@domain.com
Ergebnis:
su: invalid option -- 1
Dies sollte nicht der Fall sein, wenn Anführungszeichen dort verbleiben, wo sie eingefügt wurden. Ich habe auch versucht, "eval" zu verwenden, nicht viel Unterschied. Wenn ich den dry_run-Aufruf in email_admin entferne und dann das Skript ausführe, funktioniert es hervorragend.
Antworten:
Versuchen Sie es mit
\"
statt nur"
.quelle
"$@"
sollte arbeiten. Tatsächlich funktioniert es bei mir in diesem einfachen Testfall:Ausgabe:
Zum Hinzufügen bearbeitet: Die Ausgabe von
echo $@
ist korrekt. Das"
ist ein Metazeichen und nicht Teil des Parameters. Sie können beweisen , dass es richtig funktioniert durch Zugabeecho $5
zudry_run()
. Es wird alles danach ausgegeben-c
quelle
Dies ist kein triviales Problem. Shell führt vor dem Aufrufen der Funktion eine Anführungszeichenentfernung durch, sodass die Funktion die Anführungszeichen auf keinen Fall genau so neu erstellen kann, wie Sie sie eingegeben haben.
Wenn Sie jedoch nur eine Zeichenfolge ausdrucken möchten, die kopiert und eingefügt werden kann, um den Befehl zu wiederholen, können Sie zwei verschiedene Ansätze wählen:
eval
und übergeben Sie diese Zeichenfolge andry_run
dry_run
vor dem Drucken die Sonderzeichen des Befehls anVerwenden von
eval
So können Sie
eval
genau drucken, was ausgeführt wird:Ausgabe:
Beachten Sie die verrückte Menge an Zitaten - Sie haben einen Befehl innerhalb eines Befehls innerhalb eines Befehls, der schnell hässlich wird. Achtung: Der obige Code hat Probleme, wenn Ihre Variablen Leerzeichen oder Sonderzeichen (wie Anführungszeichen) enthalten.
Sonderzeichen zitieren
Dieser Ansatz ermöglicht es Ihnen, Code natürlicher zu schreiben, aber die Ausgabe ist für Menschen schwieriger zu lesen, da die schnelle und schmutzige Methode
shell_quote
implementiert ist:Ausgabe:
Sie können die Lesbarkeit der Ausgabe verbessern, indem Sie
shell_quote
zu Sonderzeichen mit umgekehrten Schrägstrichen wechseln , anstatt alles in einfache Anführungszeichen zu setzen. Dies ist jedoch schwierig.Wenn Sie den
shell_quote
Ansatz ausführen, können Sie den Befehl so konstruieren, dasssu
er sicherer übergeben wird. Die folgende funktionieren würde, auch wenn${GIT_WORK_TREE}
,${mail_subject}
oder${admin_email}
enthalten sind Sonderzeichen (Apostrophe, Leerzeichen, Sternchen, Semikolons, etc.):Ausgabe:
quelle
Das ist schwierig, Sie könnten diesen anderen Ansatz ausprobieren, den ich gesehen habe:
Auf diese Weise setzen Sie DRY_RUN oben in Ihrem Skript entweder auf leer oder auf "Echo" und es tut es entweder oder gibt es einfach wieder.
quelle
Schöne Herausforderung :) Es sollte "einfach" sein, wenn Sie Bash in letzter Zeit genug haben, um
$LINENO
und zu unterstützen$BASH_SOURCE
Hier ist mein erster Versuch, in der Hoffnung, dass er Ihren Bedürfnissen entspricht:
quelle