Ich schreibe über ein riesiges Skript-Factory-Skript, das viele Wartungsskripte für meine Server generiert.
Bis jetzt schreibe ich einige Zeilen, die in einer Zeile mit echo -ne
z
echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
if(($COUNT != 0))
then
echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
fi
echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
COUNT=$((COUNT+1))
JOBSDONE=$((JOBSDONE+1))
updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"
echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
Dies erzeugt mir (wenn sich zB 2 Server in meiner Konfigurationsdatei befinden) Code wie
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Alle anderen Codeblöcke, die dieses Inline-Schreiben von Code nicht benötigen, produziere ich mit Heredocs, da ich finde, dass sie viel besser zu schreiben und zu pflegen sind. ZB nach dem oberen Code habe ich den Rest wie generiert
cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
EOF
Der letzte Codeblock sieht also so aus
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
Meine Frage
Gibt es eine Möglichkeit, wie sich ein Heredoc ähnlich verhält wie echo -ne
ohne das Zeilenende-Symbol?
sudo
in einem Skript etwas falsch machen müssen: Führen Sie stattdessen das gesamte Skript als root aus!sudo -u USERNAME
auf , dass statt findet Wie kann ich einen ‚sudo‘ Befehl in einem Skript ausführen? .sudo
ohne Benutzernamen fragt nach dem Passwort, es sei denn, Sie haben es eingegeben, es gibt eine Verzögerung. Es ist noch schlimmer, wenn Sie das Skript nicht in einem Terminal ausführen, dann können Sie nicht einmal die Kennwortabfrage sehen und es wird einfach nicht funktionieren. Dersudo -u
Ansatz hat keines dieser Probleme.Antworten:
Nein, Heredoc endet immer in einer neuen Zeile. Sie können den letzten Zeilenumbruch jedoch weiterhin entfernen, z. B. mit Perl:
-p
liest die Eingabe zeilenweise, führt den in angegebenen Code aus-e
und druckt die (möglicherweise geänderte) Zeilequelle
Die kurze Antwort lautet, dass Heredoc und Herestrings nur auf diese Weise erstellt wurden. Nein, Here-Doc und Herestring fügen immer eine nachgestellte Newline hinzu, und es gibt keine Option oder native Möglichkeit, sie zu deaktivieren (möglicherweise gibt es sie in zukünftigen Bash-Versionen?).
Eine Möglichkeit, dies nur über Bash zu erreichen, besteht darin, zu lesen, was Heredoc über die Standardmethode gibt
while IFS= read -r
, aber eine Verzögerung hinzuzufügen und die letzte Zeileprintf
ohne die nachfolgende neue Zeile zu drucken. Folgendes könnte man nur mit Bash machen:Was Sie hier sehen, ist die übliche while-Schleife mit
IFS= read -r line
Annäherung, jedoch wird jede Zeile in einer Variablen gespeichert und somit verzögert (daher überspringen wir das Drucken der ersten Zeile, speichern sie und beginnen erst dann mit dem Drucken, wenn wir die zweite Zeile gelesen haben). Auf diese Weise können wir die letzte Zeile erfassen. Wenn bei der nächsten Iterationread
der Exit-Status 1 zurückgegeben wird, wird die letzte Zeile ohne Zeilenumbruch über gedrucktprintf
. Ausführlich? Ja. Aber es funktioniert:Beachten Sie, dass das
$
Eingabeaufforderungszeichen nach vorne verschoben wird, da keine neue Zeile vorhanden ist. Als Bonus ist diese Lösung portabel und POSIX-artig, daher sollte sie auch inksh
und funktionierendash
.quelle
Ich empfehle Ihnen, einen anderen Ansatz zu versuchen. Anstatt Ihr generiertes Skript aus mehreren Echoanweisungen und Heredocs zusammenzusetzen. Ich schlage vor, Sie versuchen, einen einzelnen Heredoc zu verwenden.
Sie können die Variablenerweiterung und Befehlssubstitution in einem Heredoc verwenden. Wie in diesem Beispiel:
Ich finde, dass dies oft zu viel besser lesbaren Endergebnissen führt, als die Ausgabe Stück für Stück zu produzieren.
Es sieht auch so aus, als hätten Sie die
#!
Zeile am Anfang Ihrer Skripte vergessen . Die#!
Zeile ist in korrekt formatierten Skripten obligatorisch. Der Versuch, ein Skript ohne die#!
Zeile auszuführen , funktioniert nur, wenn Sie es von einer Shell aus aufrufen, die schlecht formatierte Skripte umgeht, und selbst in diesem Fall wird es möglicherweise von einer anderen Shell interpretiert, als Sie beabsichtigt haben.quelle
#!
aber mein Codeblock ist nur ein Ausschnitt aus einem 2000-Zeilen-Skript. Ich sehe derzeit nicht, wie Ihr Vorschlag mein Problem löst, eine Codezeile in einer while-Schleife zu$( ...command...)
innerhalb eines Heredocs verwenden, um die Ausgabe dieser Befehle an dieser Stelle im Heredoc inline einzufügen. (3) Bash verfügt über Array-Variablen, die Sie inline erweitern und bei Bedarf durch Ersetzungen am Anfang / Ende hinzufügen können. Zusammen machen diese den Vorschlag von Kasperd viel leistungsfähiger (und Ihr Skript möglicherweise viel lesbarer).Heredocs enden immer in neuen Zeilen, aber Sie können diese einfach entfernen. Der einfachste Weg, den ich kenne, ist mit dem
head
Programm:quelle
-c
auch negative Werte annimmt! So noch mehr als diepearl
LösungSie können die Zeilenumbrüche nach Belieben entfernen. Die Weiterleitung ist
tr
wahrscheinlich am einfachsten. Dies würde natürlich alle Zeilenumbrüche entfernen.Für die if- Anweisung, die Sie erstellen, ist dies jedoch nicht erforderlich. Der arithmetische Ausdruck
(( .. ))
sollte auch dann einwandfrei funktionieren, wenn er Zeilenumbrüche enthält.Also könntest du es tun
produzieren
Es ist jedoch immer noch hässlich, es in einer Schleife zu bauen. Das
|| 0
ist natürlich da, damit wir die erste oder letzte Zeile nicht als Sonderfall verwenden müssen.Das haben Sie auch
| sudo tee ...
in jeder Ausgabe. Ich denke, wir könnten das beseitigen, indem wir eine Umleitung nur einmal öffnen (mit Prozessersetzung) und diese für den späteren Druck verwenden:Und ehrlich gesagt denke ich immer noch, dass das Erstellen von Variablennamen aus Variablen im äußeren Skript (so
\$${name}_E
) etwas hässlich ist und wahrscheinlich durch ein assoziatives Array ersetzt werden sollte .quelle