
Beim Versuch, einige Skripte ehemaliger Mitarbeiter meiner jetzigen Firma zu entziffern, stieß ich in vielen dieser Skripte auf die folgenden Anweisungen, die einigen Befehlen Variablen zuweisen, wie unten gezeigt:
CAT=cat
GREP=grep
SED=sed
Später im Skript sehe ich, dass sie diese Variablen anstelle der regulären Befehle verwendet haben:
$GREP -v "^#" `dirname $0`/abcdfilename | while read line
do
<some loop operations>
done
Ich sehe keinen Sinn darin, diese Variable zu verwenden, anstatt grep
direkt zu verwenden. Meine Fragen sind:
- Hat es einen Sinn, grep oder sed (in unserem Fall) auf diese Weise auszuführen?
- Ist dies das Ergebnis des Versuchs einer Person, ein Skript mit der Absicht zu schreiben, es für eine andere Person schwerer verständlich zu machen?
- Oder ist dies einfach ein Beispiel für schlechtes Scripting?
Antwort1
Es gibt auf einem System verschiedene Implementierungen für einen Standardbefehl. In Solaris 10 und früheren Versionen gibt es beispielsweise /bin/sh
die alte Bourne-Shell und /usr/xpg4/bin/sh
eine POSIX-kompatible Shell. Unter OSX gibt es beim Aufruf BSD sed sed
und beim Aufruf GNU sed gsed
. Sie können wählen, welche Implementierung Sie in Ihrem Skript verwenden möchten.
Daher ist es einfacher, die Implementierung in Ihrem Skript zu ändern, wenn Sie Variablen verwenden. Wenn Sie GNU sed möchten:
SED=gsed
Wenn Sie keine Variablen verwenden, müssen Sie alle Vorkommen von sed
in Ihrem Skript ersetzen. Obwohl dies problemlos möglich ist, gilt es als schlechte Programmierpraxis.
Antwort2
Es gibt ein Argument dafür, fast alles, was Sie in einem Skript wiederholt verwenden, in eine Variable umzuwandeln, weil Sie es dann einmal neu definieren und es im restlichen Skript wirksam einsetzen können.
Sie könnten argumentieren, dass im Grunde dasselbe mit einer einfachen Suchen/Ersetzen-Funktion von sed erreicht werden könnte, aber viele Benutzer sind bei Suchen/Ersetzen vorsichtig, da es nicht so schwer ist, versehentlich etwas zu ersetzen, was man nicht ersetzen wollte.
Tatsächlich würde ich diese Verbesserung gegenüber der bestehenden Version vorschlagen:
GREP=${GREP:-/bin/grep}
Das bedeutet, dass GREP auf den vom Benutzer in der Shell festgelegten Wert eingestellt wird. Wenn dieser Wert NICHT festgelegt ist, wird er auf /bin/grep eingestellt.
Auf diese Weise kann ein Benutzer „grep“ im laufenden Betrieb außer Kraft setzen.
$ export GREP=/bin/fgrep
$ ./path/to/script.sh
Antwort3
Es handelt sich wahrscheinlich um ein Beispiel für vorzeitige Optimierung.
Wie viele Alternativen bietet diese Maschine, oderbeliebigMaschine haben fürsed,grep, Undawk? Ich würde wetten, dass der universelle Durchschnitt nahe bei 1,0 liegt. Wenn man zwei Möglichkeiten auf einem bestimmten Rechner hat, wie hoch ist die Wahrscheinlichkeit, dass die Implementierungen so unterschiedlich sind, dass das Skript mit der im PATH gefundenen Version fehlschlägt und mit der anderen funktioniert? Wenn das passiert, ist die Lösung dann eher eine Änderung des Skripts oder des PATHs? Wenn sich die Änderung des Skripts als die Antwort erweist, wie hoch ist dann die Wahrscheinlichkeit, mindestens einen Aufruf vongrepanstatt$GREP? Die Karten sind gegen die Notwendigkeit jeglicher Indirektion gemischt, und auch dagegen, dass sie wie vorgesehen funktioniert, falls sie jemals nötig sein sollte.
Ich würde nicht gegen diese Kultur ankämpfen. Wenn es in Ihrem Geschäft eine Vorliebe für$GREPoder/usr/bin/grepoder nurgrep, ich würde wahrscheinlich mitmachen, um mitzukommen. Ansonsten gilt KISS: Vermeiden Sie Indirektion, bis die Notwendigkeit dafür entsteht.