Immer wieder dieselbe langweilige Kombination aus Usernamen und Passwort zu tippen, kann auf Dauer ganz schön ermüden. Bei FTP-Downloads spart die textbasierte Makrosprache eine Menge Tipparbeit.
Der De-facto-Standard für die Übertragung von Dateien via Internet heißt FTP (File Transfer Protocol). Das Protokoll existiert schon seit vielen Jahren, und obwohl es nicht besonders sicher ist, hat es aufgrund seiner Robustheit und Beliebtheit wohl noch eine lange Zukunft vor sich. Dieser Artikel verrät, wie Sie mit Hilfe eines Skripts eine Verbindung zu FTP-Servern aufbauen und Dateien herunterladen können.
<C>.netrc<C> richtig eingesetzt
Egal, ob Sie FTP im Batch- oder interaktiven Modus verwenden: Eine automatische Anmeldung bei der Gegenstelle spart das lästige Eintippen von Username und Passwort. Dafür sorgt eine Datei namens .netrc in Ihrem Home-Verzeichnis. Stellen Sie die Berechtigungen für .netrc auf Lesen/Schreiben nur für den Dateibesitzer (chmod 600): Benutzernamen und Passworte lagern dort im Klartext.
Die Datei kann mehrere Einträge für Remote-Sites enthalten. Sobald Sie eine .netrc besitzen und einen FTP-Befehl für eine dort aufgeführte Maschine eingeben, greift FTP auf den Benutzernamen und das Passwort des Eintrags zurück.
Die Einträge in der .netrc müssen in keinem bestimmten Format vorliegen; Sie können die einzelnen Informationen können wahlweise durch Leerzeichen, Tabulatoren oder Zeilenumbrüche trennen. Recht übersichtlich fällt aber die Variante unter Verwendung von Zeilenumbrüchen aus:
machine RemoteHost
login LoginName
password Passwort
password PasswortFuerKonto
Für jeden Remote-Host enthält die Datei einen Eintrag. Als Passwort geben Sie das für den Aufbau der Verbindung erforderliche Passwort an. Ein PasswortFuerKonto brauchen Sie nur dann, wenn der Remote-Host eine zusätzliche Authentifizierung verlangt – in der Regel genügen die ersten drei Einträge.
Listing 1 zeigt eine .netrc mit drei Einträgen, wobei hier alle Daten für eine Gegenstelle in einer Zeile stehen. Beim ersten Eintrag handelt es sich um einen öffentlichen FTP-Server im Web, deshalb der Loginname anonymous. Obwohl es als höflich gilt, die eigene E-Mail-Adresse als Passwort für die anonyme Anmeldung anzugeben, ist das nicht zwingend erforderlich. Die beiden anderen Zeilen stehen für Hosts im internen Netzwerk.
Listing 1
machine ftp.emea.ibm.com login anonymous password david.tansley@btinternet.com machine uk01lx6001 login dxtans password lOopy machine uk04lx6003 login dxtans password mas123
Um eine Verbindung zum Host uk01lx6001 aufzubauen, geben Sie ftp uk01lx6001 ein. Der FTP-Client sucht dann in .netrc nach dem Hostnamen uk01lx6001. Anschließend setzt er die Login- und Passworteinträge für den Verbindungsaufbau am Remote-Server ein. Einen Überblick über die Startoptionen des FTP-Kommandos gibt die Tabelle “FTP-Optionen”.
FTP-Optionen
| Option | Bedeutung |
|---|---|
| -p | Verwendet für Datenübertragung den so genannten passiven Modus. Er ist erste Wahl, wenn Ihr Rechner hinter einer Firewall steht, weil der Client dann dem Server den zu nutzenden Port mitteilt. Heute gilt der passive Modus als Standard, aber es gibt noch ältere Versionen, die diesen Modus nicht als Voreinstellung wählen. |
| -i | Damit fragt der Client vor jedem FTP-Transfer noch einmal nach einer Bestätigung. Wenn Sie wissen, welche Dateien Sie abholen oder schreiben wollen, ist diese Option sehr nützlich. |
| -n | Unterbindet die automatische FTP-Anmeldung beim Verbindungsaufbau. Wenn Auto-Login aktiviert ist, sucht FTP in .netrc nach den Login-Daten. Findet FTP keine passenden Informationen in .netrc, fragt es nach Benutzernamen und Passwort. |
| -v | Setzt den so genannten Verbose-Modus, in dem FTP etwas detailliertere Informationen ausgibt. |
Wie man Dateien abholt
Das erste FTP-Skript soll eine Verbindung zu einem Remote-Host aufbauen und die Datei /etc/hosts herunterladen (siehe Listing 2). Die erste Zeile nach dem Bash-Aufruf schaltet den interaktiven Modus von FTP aus und den Verbose-Modus ein.
Um ftp mit Befehlen zu füttern, kommt anschließend ein so genanntes Here-Dokument zum Einsatz. Alle Kommandos zwischen der Startmarke <<EOCMDS und der gleichnamigen Schlussmarke EOCMDS übergibt die Shell dem FTP-Client als Eingabe. Statt EOCMDS können sie dabei einen beliebigen Namen für die Marke verwenden.
Zunächst baut die Befehlsfolge eine Verbindung zum Host uk01lx6001 auf. Anschließend legt das Skript für die Übertragung mit ascii den ASCII-Modus fest. Lokal wechselt das Skript ins Verzeichnis /tmp, auf der Gegenseite nach /etc. Dann findet die eigentliche Übertragung der Datei hosts statt, die das Skript im Verzeichnis /tmp ablegt. Der Befehl quit beendet den FTP-Client.
Listing 2
#!/bin/bash ftp -i -v <<EOCMDS open uk01lx6001 ascii lcd /tmp cd /etc get hosts quit EOCMDS
Sie können die Methode auch verwenden, um eine Liste der zu übertragenden Dateien anzugeben. Allerdings müssen Sie dann für jeden Transfer eine Verbindung auf- und wieder abbauen. Wie das funktioniert, zeigt Listing 3. Eine for-Schleife innerhalb des FTP-Codeblocks können Sie deshalb nicht verwenden, weil Sie an dieser Stelle mit der FTP-Verbindung zum Remote-Host arbeiten und nicht mit der Bash-Shell.
Listing 3
#!/bin/bash
list="hosts hosts.allow hosts.deny"
for files in ${list}; do
ftp -i -v <<EOCMDS
open uk01lx6001
ascii
lcd /tmp
cd /etc
get ${files}
quit
EOCMDS
done
<C>.netrc<C>-Tricks
Sie können in Ihrem Bash-Skript prüfen, ob .netrc existiert, und davon abhängig die Authentifizierungsmethode wählen. Listing 4 enthält dafür einen einfachen Test für das .netrc-Format aus Listing 1. Existiert die Datei .netrc und ist sie lesbar, übergibt das Script die Einträge an die Standardausgabe.
Listing 4
#!/bin/bash
netrc_file=$HOME/.netrc
if [ -r ${netrc_file} ]; then
cat ${netrc_file} | awk '{print $2,$4}'
else
echo "${netrc_file} not present"
fi
Um mit einem Shell-Skript eine Auswahl aus mehreren .netrc-Einträgen (wie in Listing 1) zu erzeugen, können Sie die Datei mit Hilfe von cat an die Standardausgabe übergeben. Die Option -n von Cat fügt noch Zeilennummern hinzu. Listing 5 zeigt eine mögliche Implementierung dafür.
Listing 5
#!/bin/bash
# ftp5
netrc_file=${HOME}/.netrc
if [ -r ${netrc_file} ]; then
max_recs=$(cat ${netrc_file} | awk 'END{print NR}')
cat -n ${netrc_file} | awk '{print $1,": connect to [",$3,"] as user [",$5,"]"}'
echo -en "\n Select record to use [ 1 .. ${max_recs} ] : "
read ans
if [ ${ans} -ge 1 ] && [ ${ans} -le ${max_recs} ]; then
host=$(cat ${netrc_file} | awk "NR==$ans"|awk '{print $2}')
user=$(cat ${netrc_file} | awk "NR==$ans"|awk '{print $4}')
password=$(cat ${netrc_file} | awk "NR==$ans"|awk '{print $6}')
else
echo "invalid choice, needs to be [ 1 .. ${max_recs} ]"
exit 1
fi # $ans in numeric range
echo -e " selected info is:\n host [${host}]\n user [${user}]\n password [${password}]"
else
echo " Sorry, cannot read ${netrc_file}"
fi # netrc present
Als erstes stellt das Skript wie im letzten Beispiel sicher, dass .netrc existiert und lesbar ist. Der dann folgenden Befehl zählt die Anzahl der Einträge in der Datei und legt sie in der Variablen max_recs ab. Der Befehl wc -l wäre zwar weniger aufwändig gewesen, aber leider verwendet er beim Ersetzen der Variablen Füllzeichen, sodass der Output über die Standardausgabe nicht sehr schön aussieht.
Der cat-Befehl gibt für alle Einträge lediglich die Host- und Login-Felder jedes Eintrags über die Standardausgabe aus (Abbildung 1). Als nächstes fordert das Skript den Benutzer dazu auf, die Nummer des Eintrags einzugeben, den er wählen möchte. Dabei greift es auf die oben belegte Variable max_recs zurück, die die Anzahl an Einträgen enthält. Nach der Auswahl liest das Skript auf Basis der Input-Nummer die erforderlichen Felder mit Hilfe der Awk-Funktion NR aus und zeigt das Ergebnis an.
Das Skript verzichtet weitgehend auf die Fehlerbehandlung – es stellt lediglich fest, ob die eingegebene Zahl innerhalb des gültigen numerischen Bereichs liegt.
Fehlerbehandlung
Wenn Sie den Fehlerstatus am Ende des FTP-Scripts abfragen wollen, können Sie auf die FTP-Fehlernummern zurückgreifen. In der Tabelle “FTP-Rückgabewerte” finden Sie die standardisierten Rückgabe-Codes.
FTP-Rückgabewerte
| Code | Bedeutung |
|---|---|
| 202 | Befehl nicht implementiert |
| 421 | Dienst nicht verfügbar |
| 426 | Transfer abgebrochen |
| 450 | Datei nicht verfügbar |
| 500 | Syntaxfehler |
| 501 | Syntaxfehler in Argumenten |
| 503 | Benutzer nicht angemeldet |
| 550 | Datei nicht verfügbar |
| 553 | Ungültiger Dateiname |
| 666 | Datei oder Verzeichnis existiert nicht |
| 777 | Unbekannter Host |
| 999 | Ungültiger Befehl |
Eine Möglichkeit, Fehlerbedingungen abzufangen, besteht darin, am Ende des Scripts egrep aufzurufen (siehe Listing 6). Als erstes müssen Sie die gesamte FTP-Ausgabe in eine Log-Datei umleiten:
ftp -i -v >> ${log} 2>&1
FTP leitet die gesamte Ausgabe, einschließlich aller während der FTP-Session auftretenden Fehler, in das Logfile, dessen Name in der Variable log steht. Am Ende der FTP-Session durchsuchen Sie die Datei mithilfe von Egrep nach interessanten Codes oder Begriffen; dabei trennt jeweils eine Pipe (|) die Suchmuster. Setzen Sie Egrep innerhalb eines Skripts ein, dann macht es Sinn, die Ausgabe der Suchroutine auf /dev/null umzuleiten; damit halten Sie die Standardausgabe frei von unerwünschtem Output:
if egrep "202|421|426" $log > /dev/null 2>&1
Wenn Egrep für einen Treffer true meldet, terminiert das Skript aus Listing 6 mit dem Rückgabewert 1, gibt eine Meldung auf der Konsole aus und schreibt diese auch ins Logfile. Andernfalls gibt das Skript 0 zurück.
Falls Sie das Skript als Batch ausführen, statt interaktiv aus der Befehlszeile, sollten Sie die Ausgabe nur in die Log-Dateien schreiben, nicht aber über den Befehl tee auch auf die Standardausgabe. In diesem Fall ändern Sie die entsprechenden Zeilen aus Listing 6 in echo "Errors" >> ${log} im Fehlerfall und echo "OK" >> ${log} für eine Erfolgsmeldung.
Listing 6
…
for files in ${list}; do
ftp -i -v >> ${log} 2>&1 <<EOCMDS
…
EOCMDS
done
if egrep "202|421|426|450|500|501|503|550|553|666|777|999" ${log} > /dev/null 2>&1; then
echo "Errors" | tee -a ${log}
exit 1
else
echo "OK" | tee -a ${log}
exit 0
fi
Fazit
Das Automatisieren von FTP bietet viele produktive Möglichkeiten für den Dateiaustausch zwischen Hosts. Experimentieren Sie ruhig mit unterschiedlichen FTP-Skripts, um verschiedene administrative Aufgaben zu erfüllen. Schreiben Sie dazu aber in jedem Fall die Benutzernamen und Passwörter in die nicht für jeden lesbare Datei .netrc, statt sie im Skript einzubetten.





