Shell-Skripte und Verzeichniswechsel: Warum Dein Skript nicht das Verzeichnis wechselt – und wie Du das Problem löst

Vielleicht kennst Du das Problem: Du hast unter Ubuntu oder Linux Mint ein einfaches Shell-Skript geschrieben, das nur das Verzeichnis wechseln soll. Doch beim Aufruf des Skripts merkst Du, dass das Verzeichnis in Deiner aktuellen Shell nicht gewechselt wird, obwohl der cd-Befehl im Skript steht.

In diesem Artikel erkläre ich Dir, warum das passiert und wie Du es richtig machst.

Das Problem: Skripte laufen in einer Subshell

Wenn Du ein Shell-Skript normal ausführst, passiert das in einer Subshell. Das bedeutet, dass eine neue Shell-Instanz geöffnet wird, die das Skript abarbeitet. Sobald das Skript fertig ist, wird die Subshell geschlossen und Du landest wieder in Deiner ursprünglichen Shell – ohne dass Änderungen wie der Verzeichniswechsel übernommen werden.

Das ist der Grund, warum Dein cd-Befehl zwar innerhalb des Skripts funktioniert, aber nach dem Ende des Skripts Dein Verzeichnis unverändert bleibt.

Die Lösung: Das Skript im aktuellen Shell-Kontext ausführen

Damit das Verzeichnis in Deiner aktuellen Shell geändert wird, musst Du das Skript im aktuellen Shell-Kontext ausführen. Dazu gibt es zwei einfache Möglichkeiten: den Befehl source oder den Punkt ..

Beispiel:

Nehmen wir an, Du hast ein Skript namens wechselverzeichnis.sh, das so aussieht:

#!/bin/bash
cd /pfad/zu/deinem/verzeichnis

Anstatt es wie gewohnt so aufzurufen:

./wechselverzeichnis.sh

musst Du es so aufrufen:

source wechselverzeichnis.sh

oder:

. wechselverzeichnis.sh

Was passiert beim „Sourcen“?

Durch den Aufruf mit source (oder dem Punkt .) wird das Skript nicht in einer Subshell ausgeführt, sondern direkt im Kontext Deiner aktuellen Shell. Alle Änderungen, die das Skript an der Umgebung vornimmt, wie z.B. der Verzeichniswechsel, gelten dann auch für Deine Shell-Sitzung.

Was ist, wenn ich das Skript normal ausführen will?

Wenn Du das Skript weiter wie gewohnt ausführst, also mit ./wechselverzeichnis.sh, dann bleibt es dabei, dass es in einer Subshell läuft. Das kann für andere Arten von Skripten völlig ausreichend sein, aber für Dinge wie cd, die Änderungen an der aktuellen Umgebung vornehmen sollen, ist es nicht die richtige Methode.

Fazit

Wenn Du ein Shell-Skript geschrieben hast, das in Deinem aktuellen Shell-Kontext Änderungen vornehmen soll, wie z.B. den Wechsel des Verzeichnisses mit cd, dann musst Du das Skript „sourcen“ – also mit source oder . aufrufen. Dadurch führst Du das Skript im gleichen Kontext aus, und die Änderungen gelten direkt für Deine aktuelle Shell-Sitzung.

Datensicherung für Ubuntu-Server verschlüsselt auf Strato HiDrive

Eine automatische, nächtliche Datensicherung für einen Ubuntu-Server ist schnell eingerichtet. Dabei werden die Daten lokal verschlüsselt und dann per SFTP verschlüsselt auf einen Strato HiDrive-Account übertragen. Dazu verwende ich das Linux-Tool Duplicity.

Zunächst richtet man ein kleines Shell-Skript ein und legt es im eigenen Home-Verzeichnis an. Mein Beispiel-Skript führt monatlich eine vollständige Datensicherung durch. Alle weiteren nächtlichen Sicherungen erfolgen dann inkrementell. Außerdem lasse ich durch Duplicity automatisch alle Sicherungen entfernen, die älter als 3 Monate sind. So muss ich mir keine Gedanken darüber machen, dass der Strato HiDrive-Speicher auf Dauer vollläuft.

#!/bin/bash
export PASSPHRASE="MeineStrengGeheimePassphrase"
export FTP_PASSWORD=<SFTP-Passwort von Strato>

# monatliche Vollsicherung (1M)
duplicity --full-if-older-than 1M /home/user sftp://share-xxxx@sftp.hidrive.strato.com/users/share-xxxx/Serversicherungen

# Backups wegräumen, die älter als 3 Monate sind
duplicity remove-older-than 3M --force sftp://share-xxxx@sftp.hidrive.strato.com/users/share-xxxx/Serversicherungen

unset PASSPHRASE
unset FTP_PASSWORD

Hier sind nur noch die markierten Stellen individuell anzupassen bzw. mit den Strato-Zugangsdaten zu füllen.

Beim ersten Aufruf muss man zunächst den SSH-Fingerabdruck des Strato-Server bestätigen. Dieser wird dabei in der .ssh/known_hosts abgelegt. Daher sollte man das Sicherungsskript einmal manuell durchlaufen lassen, bevor man die Datensicherung als Cronjob anlegt. Ist der SSH-Fingerabdruck hinterlegt, läuft das Sicherungsskript ohne weitere Nachfrage automatisch durch.

Dieses Sicherungsskript kann man nun z.B. über einen Cronjob jede Nacht  um 23:00 Uhr aufrufen. Um einen solchen Cronjob anzulegen, wechselt man mit crontab -e in den Cronjob-Editor und legt folgende neue Zeile an:

0 23 * * * /home/user/backup.sh >> /home/user/logs/backup.log 2> /home/user/logs/backup.error.log

Dabei ist darauf zu achten, dass das logs-Verzeichnis bereits angelegt und schreibbar ist, da die Datensicherung sonst fehlschlägt.

Für die Wiederherstellung der so gesicherten Daten habe ich ein kleines Restore-Skript zusammengestellt, das ich im Notfall nur noch schnell anpassen muss, ohne erst zu recherchieren, wie genau eine Datenwiederherstellung mit Duplicity funktioniert.

export PASSPHRASE="MeineStrengGeheimePassphrase"
export FTP_PASSWORD=<SFTP-Passwort von Strato>

duplicity restore sftp://share-xxxx@sftp.hidrive.strato.com/users/share-xxxx/Serversicherungen /home/user/backup

unset PASSPHRASE
unset FTP_PASSWORD

Die beiden Skriptdateien sollte man dann noch mit einem chmod 700 backup.sh bzw. chmod 700 restore.sh vor den neugierigen Blicken anderer User auf dem System schützen.