Was ist falsch an diesem Skript?

Was ist falsch an diesem Skript?

Ich habe dieses Skript aus diesem Handbuch: www.tldp.org/LDP/abs/abs-guide.pdf

LOG_DIR=/var/log
ROOT_UID=0
LINES=50
E_XCD=86
E_NOTROOT=87

if [ "$UID" != "$ROOT_UID" ]
then
echo "Must be root to run this script."
exit $E_NOTROOT
fi

if [ -n "$1" ]
then
lines=$1
else
lines=$LINES
fi

cd $LOG_DIR

if [ 'pwd' != "$LOG_DIR" ]
then
echo "Can't change to $LOG_DIR."
exit $E_XCD
fi

Jetzt habe ich „sudo su“ im Terminal ausgeführt und $UID ausgegeben, was mir 0 gibt. Das bedeutet, dass meine if-Bedingung sich als falsch herausstellt, ich aber trotzdem die Meldung „Zum Ausführen dieses Skripts müssen Sie Root sein“ erhalte, während ich dieses Skript ausführe.

Auch im Originalskript wurde diese „if“-Bedingung wie folgt angegeben:

if [ "$UID" -ne "$ROOT_UID" ]

aber ich erhielt die Fehlermeldung „Ungültige Zahl“, weil -ne anscheinend nur für Zeichenfolgen verwendet wird, also habe ich es in != geändert.

Antwort1

Anstatt es auszuführen mit

sh script.sh

Führen Sie es aus mit

bash script.sh

#!/bin/bash(oder als erste Zeile hinzufügen, um den Interpreter festzulegen).

Die shShell in Ubuntu istnicht bash, aber eine separate Shell namens dash. dashhat nicht so viele Funktionen wie bash, was sie effizienter macht, aber diese fehlenden Funktionen beschädigen manchmal Skripte, die für gedacht sind bash. Eine solche Funktion ist die $UIDVariable, dienicht definiertIn dash.

Das bedeutet, dass der Vergleich bei Ausführung des Skripts in dashzu führt ["" != "0"], was unabhängig vom Benutzer, der es ausführt, als wahr ausgewertet wird. Wenn es jedoch bashmit Root-Berechtigungen ausgeführt wird, sind die Zeichenfolgen gleich und das Skript funktioniert.

Antwort2

AlsMcLovin sagt, die automatisch gesetzte, schreibgeschützte UID(und EUID) Variable ist eine Besonderheit vonbash(und einige andere Shells). Es ist kein Standard fürShells im Bourne-Stilund shkann nicht davon ausgegangen werden, diese Variablen zu setzen. Insbesondere shin Ubuntu ist (derzeit standardmäßig)dash, das sie nicht setzt.

Sie haben zwei Möglichkeiten:

  1. bashBewirken Sie, dass Ihr Skript von statt von ausgeführt wird sh.
  2. Ändern Sie Ihr Skript, damit es portabler ist und nicht erfordert bash.

Ausführen Ihres Skripts mitbash

Du hast uns den Namen deines Skripts nicht verraten (was in Ordnung ist). Ich werde es nennencleanup, da dies der Name des ähnlichen Skripts in dem Handbuch ist, mit dem Sie arbeiten.

Beachten Sie insbesondere, dass ichnichtNennen Sie es etwa so cleanup.sh. Das liegt daran, dass ich nicht empfehle, es mit einem .shSuffix zu benennen:

  • Ein .shSuffix weist auf die Kompatibilität mit sh! hin.
  • Die meisten Skripte erhalten überhaupt kein Suffix, und ein Suffix .shoder .bashkann sogar so interpretiert werden, dass Ihre Datei eher eine „Bibliothek“ als ein „Top-Level“-Skript ist. Das heißt, dass es Code bereitstellt, der von anderen Skripten (z. B. mit dem .integrierten) bezogen werden kann, anstatt tatsächlich direkt ausgeführt zu werden.

Das Einfügen eines Suffixes hat jedoch .shkeinerlei Auswirkungen auf das technische Verhalten Ihres Skripts. Es sind damit weder technische Vor- noch Nachteile verbunden.

Füge hinzu einHashbang-Zeileals allererste Zeile Ihres Skripts:#!/bin/bash

Machen Sie Ihr Skript ausführbarmit .chmod +x cleanup

Jetzt kannst duFühren Sie Ihr Skript ausindem Sie den folgenden Befehl ausführen:

  • ./cleanup, wenn es sich im aktuellen Verzeichnis befindet. (Besonders beim Skripting für Bildungszwecke, Erkundung, Tests, Spaß oder andere begrenzte oder einmalige Verwendungszwecke ist dies wahrscheinlich die gebräuchlichste Methode.)

  • /path/to/cleanup, im Allgemeinen. Wenn das erste Wort eines Befehls ein enthält, /wird es als Pfad zu einer ausführbaren Datei interpretiert. (Das ist der Grund für die obige ./Syntax, denn as .bedeutet das aktuelle Verzeichnis.)

    Vonerstes WortIch meine den Befehl bis zum ersten Befehl, jedoch nicht einschließlichnicht entkommenLeerzeichen oder Tabulator:
    foo-bar/bazist das erste Wort von foo-bar/baz qux, während spam\ hamdas erste Wort von ist, spam\ ham eggsweil das Leerzeichen davor hammit einem Backslash maskiert wird.

  • cleanup, wenn es sich in einem Verzeichnis in Ihrem befindet PATH(und kein zuerst aufgeführtes Verzeichnis eine ausführbare Datei mit demselben Namen hat und diese nicht durch eineShell integriert,Funktion, oderalias).

Unabhängig davon, ob ein Skriptcleanuphat eine #!...Hashbang-Zeile oder was diese Zeile sagt:

  • sh cleanupwird immer noch (versuchen), es mit shals Interpreter auszuführen.
  • bash cleanupwird immer noch (versuchen), es mit bashals Interpreter auszuführen.

shDies liegt daran, dass Sie in diesen Fällen tatsächlich den Interpreter ( oder ) ausführen bashund den Namen des Skripts an den Interpreter übergeben, damit dieser es ausführen kann. Viele Programme akzeptieren Dateinamen, die auf der Befehlszeile geöffnet werden sollen, und Shells mögen shund bashbefolgen diese Konvention.

So machen Sie Ihr Skript portierbar

Wenn Sie Ihr Skript portierbar machen möchten, ist es am einfachsten, es $UIDüberhaupt nicht zu verwenden und stattdessen eine Funktion zu nutzen, die allen Shells im Bourne-Stil zur Verfügung steht.

Im Allgemeinen gibt es keine integrierte Shell-Funktion zur Ermittlung der Benutzer-ID. Sie können jedoch verwendenid. Dies ist ein externes Programm und kein Shell-Builtin, aber wiecatUndls, kann man davon ausgehen, dass es vorhanden sein wird.

idgibt selbst eine Menge Informationen aus, id -ugibt aber nur die tatsächliche Benutzer-ID an.

Anstelle von if [ "$UID" != "$ROOT_UID" ]können Sie also Folgendes verwenden:

if [ "$(id -u)" != "$ROOT_UID" ]

Technisch, dies ist nicht gleichwertig. $UIDin bashgibt die echte Benutzer-ID an und id -uentspricht tatsächlich bash's $EUID. Wenn Sie wirklich die UID und nicht die EUID möchten, verwenden Sie id -ru.

verwandte Informationen