Das Skript sollte in der Lage sein, in das eigene Installationsverzeichnis zu wechseln, egal wie es aufgerufen wird. Dazu wird unter Linux readlink -f verwendet. Damit wird zunächst der Installationspfad des Skripte normalisiert. Mit dirname und basename kann man dann das Installationsverzeichnis und den Skriptnamen extrahieren.
Mit GNU readlink unter Linux funktioniert das einfach und zuverlässig.
Wenn man andere Plattformen unterstützen will, muss man eventuell andere Lösungen suchen. Das BSD readlink aus dem Mac OS X unterstützt die Option -f nicht und ist somit etwas eingeschränkt. Darüber gibt es diverse Diskussionen im Internet:
https://stackoverflow.com/questions/598 ... -stored-in
https://stackoverflow.com/questions/105 ... f-on-a-mac
Auf GitHub hat jemand eine Testsuite zusammengestellt, um verschiedene Lösungen zu vergleichen:
Bash test: get the directory of a script
https://gist.github.com/tvlooy/cbfbdb111a4ebad8b93e
Die einzigen Lösungen, die zuverlässig funktionieren, sind "readlink -f" und eine "overcomplicated stackoverflow solution".
Für das Skript DownloadUpdates.sh könnte man eine ähnliche Testsuite definieren, um alle Anwendungsfälle zu testen:
- Aufruf mit bash und dem Skriptnamen: bash DownloadUpdates.sh
So würde man ein Skript eigentlich nicht aufrufen, da der Skriptinterpreter in der ersten Zeile festgelegt wird. Aber Zip-Archive, die unter Windows erstellt werden, enthalten keine Dateiberechtigungen für Linux; die Skripte sind deshalb zunächst nicht ausführbar. Deshalb heißt es auch in der Hilfe am Anfang des Skripts:
Please start this program with
bash $Prog - Direkter Aufruf aus demselben Verzeichnis: ./DownloadUpdates.sh
Das ist der einfachste Fall und sollte immer funktionieren. - Aufruf aus einem anderen Verzeichnis, gerne auch mit Leerzeichen im Pfad
- Aufruf mit einem symbolischen Link aus dem Verzeichnis ~/bin
- Rekursiver Aufruf des Skripts
Das Skript DownloadUpdates.sh ruft sich unter Umständen mehrfach selber auf:
Wenn man das Skript ohne Parameter startet, kommt man zum interaktiven Setup der Updates, Sprachen und optionalen Downloads. Danach ruft das Skript sich selber mit diesen Parametern auf.
Wenn man eine der eingebauten Listen wie "All Windows 32 bit" verwendet, ruft das Skript sich wiederum mehrfach selber auf, um diese Listen abzuarbeiten.
Eine Testsuite für ein Skript ähnlich DownloadUpdates.sh sollte alle diese Anwendungsfälle berücksichtigen.
Dazu werden zunächst fünf Skripte script_1.sh bis script_5.sh erstellt. Jedes Skript verwendet eine andere Methode, um das Arbeitsverzeichnis zu setzen. Dann gibt das Skript aus:
- die Befehlszeile, mit der es aufgerufen wurde
- das aktuelle Arbeitsverzeichnis, soweit es das Skript herausgefunden hat
- Dann soll das Skript eine andere Datei aus demselben Verzeichnis einlesen, die "Hello, World!" ausgibt.
Anschließend ruft das Skript sich mehrfach rekursiv auf, um auch diesen speziellen Anwendungsfall zu untersuchen.
Gespeichert werden die Skripte im Verzeichnis "~/tmp/WSUS Offline Update/sh". Das erwartete Ergebnis ist, dass die Skripte bei jedem Test dieses Verzeichnis "/home/anwender/tmp/WSUS Offline Update/sh" und anschließend "Hello, World!" ausgeben.
Die verwendeten Skripte sind:
Skript 1, entsprechend WSUS Offline Update 10.2
- Code: Select all
#!/bin/bash
script_name="script_1.sh"
# Print command line
echo "Command line: $0 $*"
# Resolve installation path as in WSUS Offline Update 10.2
cd $( dirname $(readlink -f "$0") )
# Print working directory
echo "Working directory: $(pwd)"
# Include another file
source "hello-world.txt"
# Simulate recursive calls
case "$1" in
"")
bash "$script_name" all-x86
;;
all-x86)
bash "$script_name" w60 glb
#bash "$script_name" w61 glb
#bash "$script_name" w62 glb
#bash "$script_name" w63 glb
#bash "$script_name" w100 glb
;;
w60 | w61 | w62 | w63 | w100)
echo "Recognized parameter $1"
;;
*)
echo "Unknown parameter 1: $1"
;;
esac
Skript 2, entsprechend WSUS Offline Update 10.2.1
- Code: Select all
#!/bin/bash
script_name="script_2.sh"
# Print command line
echo "Command line: $0 $*"
# Resolve installation path as in WSUS Offline Update 10.2.1
SCRIPT_DIR=$(readlink -f ${0%/*})
cd "$SCRIPT_DIR"
# Print working directory
echo "Working directory: $(pwd)"
# Include another file
source "hello-world.txt"
# Simulate recursive calls
case "$1" in
"")
bash "$script_name" all-x86
;;
all-x86)
bash "$script_name" w60 glb
#bash "$script_name" w61 glb
#bash "$script_name" w62 glb
#bash "$script_name" w63 glb
#bash "$script_name" w100 glb
;;
w60 | w61 | w62 | w63 | w100)
echo "Recognized parameter $1"
;;
*)
echo "Unknown parameter 1: $1"
;;
esac
Skript 3, entsprechend WSUS Offline Update trunk-r709
- Code: Select all
#!/bin/bash
script_name="script_3.sh"
# Print command line
echo "Command line: $0 $*"
# Resolve installation path as in WSUS Offline Update trunk-r709
cd "$( dirname $(readlink -f "$0") )"
# Print working directory
echo "Working directory: $(pwd)"
# Include another file
source "hello-world.txt"
# Simulate recursive calls
case "$1" in
"")
bash "$script_name" all-x86
;;
all-x86)
bash "$script_name" w60 glb
#bash "$script_name" w61 glb
#bash "$script_name" w62 glb
#bash "$script_name" w63 glb
#bash "$script_name" w100 glb
;;
w60 | w61 | w62 | w63 | w100)
echo "Recognized parameter $1"
;;
*)
echo "Unknown parameter 1: $1"
;;
esac
Skript 4, kurze und einfache Lösung
- Code: Select all
#!/bin/bash
script_name="script_4.sh"
# Print command line
echo "Command line: $0 $*"
# Resolve installation path, short and simple
cd "$(dirname "$(readlink -f "$0")")"
# Print working directory
echo "Working directory: $(pwd)"
# Include another file
source "hello-world.txt"
# Simulate recursive calls
case "$1" in
"")
bash "$script_name" all-x86
;;
all-x86)
bash "$script_name" w60 glb
#bash "$script_name" w61 glb
#bash "$script_name" w62 glb
#bash "$script_name" w63 glb
#bash "$script_name" w100 glb
;;
w60 | w61 | w62 | w63 | w100)
echo "Recognized parameter $1"
;;
*)
echo "Unknown parameter 1: $1"
;;
esac
Skript 5, längere Lösung mit Bestimmung der Verzeichnis- und Skriptnamen
- Code: Select all
#!/bin/bash
script_name="script_5.sh"
# Print command line
echo "Command line: $0 $*"
# Resolve installation path, more elaborate solution to get home directory
# and script name
canonical_name=$(readlink -f "$0")
script_name=$(basename "$canonical_name")
home_directory=$(dirname "$canonical_name")
cd "$home_directory"
# Print working directory
echo "Working directory: $(pwd)"
# Include another file
source "hello-world.txt"
# Simulate recursive calls
case "$1" in
"")
bash "$script_name" all-x86
;;
all-x86)
bash "$script_name" w60 glb
#bash "$script_name" w61 glb
#bash "$script_name" w62 glb
#bash "$script_name" w63 glb
#bash "$script_name" w100 glb
;;
w60 | w61 | w62 | w63 | w100)
echo "Recognized parameter $1"
;;
*)
echo "Unknown parameter 1: $1"
;;
esac
Aufgerufen werden sie von einem weiteren Kontrollskript:
- Code: Select all
#!/bin/bash
# Filename: control_script.sh
for script_name in script_1.sh script_2.sh script_3.sh script_4.sh script_5.sh
do
echo "Testing script: $script_name"
echo ""
echo "Invocation with \"bash $script_name\""
bash "$script_name"
echo ""
echo "Direct call of the script from within the same directory"
./"$script_name"
echo ""
echo "Calling the script from the home directory"
pushd ~ > /dev/null
"tmp/WSUS Offline Update/sh/$script_name"
popd > /dev/null
echo ""
echo "Using a symbolic link in ~/bin"
pushd ~/bin > /dev/null
if [[ ! -h "$script_name" ]]; then
ln -s "../tmp/WSUS Offline Update/sh/$script_name"
fi
"$script_name"
if [[ -h "$script_name" ]]; then
rm "$script_name"
fi
popd > /dev/null
echo ""
done
Die Textdatei hello-world.txt hat nur den Inhalt:
- Code: Select all
echo "Hello, World!"
Die gesamten Ergebnisse:
- Code: Select all
~/tmp/WSUS Offline Update/sh$ ./control_script.sh
Testing script: script_1.sh
Invocation with "bash script_1.sh"
Command line: script_1.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender
script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
bash: script_1.sh: Datei oder Verzeichnis nicht gefunden
Direct call of the script from within the same directory
Command line: ./script_1.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender
./script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
bash: script_1.sh: Datei oder Verzeichnis nicht gefunden
Calling the script from the home directory
Command line: tmp/WSUS Offline Update/sh/script_1.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender
tmp/WSUS Offline Update/sh/script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
bash: script_1.sh: Datei oder Verzeichnis nicht gefunden
Using a symbolic link in ~/bin
Command line: /home/anwender/bin/script_1.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender
/home/anwender/bin/script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_1.sh all-x86
Working directory: /home/anwender
/home/anwender/bin/script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_1.sh w60 glb
Working directory: /home/anwender
/home/anwender/bin/script_1.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Recognized parameter w60
Testing script: script_2.sh
Invocation with "bash script_2.sh"
Command line: script_2.sh
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_2.sh all-x86
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_2.sh w60 glb
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Direct call of the script from within the same directory
Command line: ./script_2.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_2.sh all-x86
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_2.sh w60 glb
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Calling the script from the home directory
Command line: tmp/WSUS Offline Update/sh/script_2.sh
readlink: zusätzlicher Operand „Offline“
„readlink --help“ gibt weitere Informationen.
Working directory: /home/anwender
tmp/WSUS Offline Update/sh/script_2.sh: Zeile 16: hello-world.txt: Datei oder Verzeichnis nicht gefunden
bash: script_2.sh: Datei oder Verzeichnis nicht gefunden
Using a symbolic link in ~/bin
Command line: /home/anwender/bin/script_2.sh
Working directory: /home/anwender/bin
/home/anwender/bin/script_2.sh: Zeile 16: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_2.sh all-x86
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/bin
script_2.sh: Zeile 16: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_2.sh w60 glb
script_2.sh: Zeile 10: cd: /home/anwender/tmp/WSUS Offline Update/sh/script_2.sh: Ist kein Verzeichnis
Working directory: /home/anwender/bin
script_2.sh: Zeile 16: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Recognized parameter w60
Testing script: script_3.sh
Invocation with "bash script_3.sh"
Command line: script_3.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_3.sh all-x86
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_3.sh w60 glb
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Direct call of the script from within the same directory
Command line: ./script_3.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_3.sh all-x86
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_3.sh w60 glb
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Calling the script from the home directory
Command line: tmp/WSUS Offline Update/sh/script_3.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender
tmp/WSUS Offline Update/sh/script_3.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
bash: script_3.sh: Datei oder Verzeichnis nicht gefunden
Using a symbolic link in ~/bin
Command line: /home/anwender/bin/script_3.sh
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/bin
/home/anwender/bin/script_3.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_3.sh all-x86
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/bin
script_3.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Command line: script_3.sh w60 glb
dirname: zusätzlicher Operand „Offline“
„dirname --help“ gibt weitere Informationen.
Working directory: /home/anwender/bin
script_3.sh: Zeile 15: hello-world.txt: Datei oder Verzeichnis nicht gefunden
Recognized parameter w60
Testing script: script_4.sh
Invocation with "bash script_4.sh"
Command line: script_4.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Direct call of the script from within the same directory
Command line: ./script_4.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Calling the script from the home directory
Command line: tmp/WSUS Offline Update/sh/script_4.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Using a symbolic link in ~/bin
Command line: /home/anwender/bin/script_4.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_4.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Testing script: script_5.sh
Invocation with "bash script_5.sh"
Command line: script_5.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Direct call of the script from within the same directory
Command line: ./script_5.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Calling the script from the home directory
Command line: tmp/WSUS Offline Update/sh/script_5.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Using a symbolic link in ~/bin
Command line: /home/anwender/bin/script_5.sh
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh all-x86
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Command line: script_5.sh w60 glb
Working directory: /home/anwender/tmp/WSUS Offline Update/sh
Hello, World!
Recognized parameter w60
Diskussion der einzelnen Ergebnisse:
Skript 1, entsprechend WSUS Offline Update 10.2
Das aktuelle Arbeitsverzeichnis wird immer falsch gesetzt, und die Textdatei hello-world.txt kann nie gefunden werden.
Skript 2, entsprechend WSUS Offline Update 10.2.1
Beim Aufruf aus demselben Verzeichnis mit "bash script_2.sh" oder "./script_2.sh" meldet cd Fehler, weil das angebliche Installationsverzeichnis kein Verzeichnis ist. Da aber kein Verzeichniswechsel benötigt wird, funktioniert es trotzdem.
Der Aufruf aus dem Home-Verzeichnis und mit einem symbolischen Link schlägt fehl.
Skript 3, entsprechend WSUS Offline Update trunk-r709
Beim Aufruf aus demselben Verzeichnis meldet dirname Fehler. Da aber kein Verzeichniswechsel benötigt wird, funktioniert es trotzdem.
Der Aufruf aus dem Home-Verzeichnis und mit einem symbolischen Link schlägt fehl.
Skript 4, kurze und einfache Lösung
Das Arbeitsverzeichnis wird immer richtig gesetzt und die Textdatei immer gelesen.
Skript 5, längere Lösung mit Bestimmung der Verzeichnis- und Skriptnamen
Das Arbeitsverzeichnis wird immer richtig gesetzt und die Textdatei immer gelesen.