rsync ssh und Passwort Eingabe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Irgendwie kennt rsync keine Option --exclude, sondern nur --exclude= mit dem Gleichheitszeichen am Ende, nur dann muss das Argument direkt nach dem Gleichheitszeichen beginnen, ansonsten erkennt er es als Quelle. Hat Jemand eine Idee?

Grüße Markus
BlackJack

@feldmaus: Was für ein ``rsync`` verwendest Du denn da? Das geht auch ohne das ``=``.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Also ich nutze rsync Version

Code: Alles auswählen

rsync  version 3.0.7  protocol version 30
Copyright (C) 1996-2009 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 32-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes
Also in der manpage steht ein Beispiel ohne "=", aber wenn ich es ohne "=" ausführe bekomme ich die Meldung

Code: Alles auswählen

rsync: --exclude : unknown option
Und mit dem "=" versucht er mein Exclude-Argument als Source zu verwenden

Code: Alles auswählen

building file list ... 

rsync: link_stat "/home/markus/bin/__ThereIsNothingToExcludeInThisSourceButINeedAnEmptyExclude__ " failed: No such file or directory (2)

rsync: link_stat "/home/markus/bin/ " failed: No such file or directory (2)

0 files to consider
Bei diesem Beispiel hat meine Quelle keine Auszuschliessenden, trotzdem verwende ich die Option "--exclude[=]", da ich mein Programm sonst auch durch eine Fallunterscheidung unnötig verkomplizieren würde. Wie auch immer, die Quellen mit Auszuschliesenden funktionieren so zumindest nicht.

Was ich nicht verstehe ist, warum er mein /home/markus/bin/ Verzeichnis nicht findet. Und von markus@server:/home/markus/bin/ (meinem Ziel-Verzeichnis) wurde hier nichts erwähnt.
BlackJack

@feldmaus: Du solltest Dich wirklich ganz dringend endlich mal damit beschäftigen wie die Übergabe von Argumenten funktioniert. Auf C-Ebene. Und was zum Beispiel eine Shell alles macht um von einer Zeile in der Shell auf eine Argumentliste auf C-Ebene zu bekommen. Genau da machst Du nämlich schon wieder Fehler.

Da steht nämlich nicht, dass ``rsync`` die Option '--exclude' nicht kennt, sondern dass es die Option '--exclude ' nicht kennt. Da ist ein Leerzeichen was da nicht hin gehört:

Code: Alles auswählen

bj@s8n:~$ rsync '--exclude'
rsync: --exclude: missing argument
rsync error: syntax or usage error (code 1) at main.c(1443) [client=3.0.7]
bj@s8n:~$ rsync '--exclude '
rsync: --exclude : unknown option
rsync error: syntax or usage error (code 1) at main.c(1443) [client=3.0.7]
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Es funktioniert :mrgreen:
BlackJack hat geschrieben:@feldmaus: Du solltest Dich wirklich ganz dringend endlich mal damit beschäftigen wie die Übergabe von Argumenten funktioniert. Auf C-Ebene. Und was zum Beispiel eine Shell alles macht um von einer Zeile in der Shell auf eine Argumentliste auf C-Ebene zu bekommen. Genau da machst Du nämlich schon wieder Fehler.
Mich mögen die Leerzeichen halt besonders gerne :mrgreen: Es funktioniert :D Es kommen aber noch einige andere Funktionen mit rein z.b. falls ein falsches Passwort eingegeben wurde.

Und hier der Code mit ungekürzten Leerzeichen :)

Code: Alles auswählen

                    PASSWORT=raw_input('Bitte Passwort fuer '+BENUTZER+' eingeben:')
                    benutzer_passwoerter[BENUTZER]=PASSWORT
                    child=rsync()
                    child.logfile = sys.stdout
                    child.expect('password:', timeout=3)
                    child.logfile = sys.stdout
                    child.sendline(PASSWORT)
                    child.logfile = sys.stdout
                    while not child.expect(pexpect.EOF):
                        PASSWORT=raw_input('Falsches Passwort!\nBitte Passwort fuer '+BENUTZER+' eingeben:')
                        benutzer_passwoerter[BENUTZER]=PASSWORT
                        child.expect('password:', timeout=3)
                        child.sendline(PASSWORT)
Nach erfolgreichem Beenden von dem rsync Befehl springt er trotzdem noch in die while-Schleife. Der Datenstrom müsste doch zu Ende sein, dann dürfte er doch auch nicht mehr in meine Schleife springen, oder interpretiere ich den Befehl child.expect(pexpect.EOF) falsch?
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Habe nun einige wichtige Sachen geändert auch hinsichtlich der Lesbarkeit. Wenn der eine oder andere noch Style-Ideen hat, dann her damit. Als nächste Änderung kommt der Fehler TIMEOUT, den ich noch nicht berücksichtigt habe.

Code: Alles auswählen

    for eintrag in katalog:
        for BENUTZER in katalog[eintrag]['Benutzer']:
            antwort2=raw_input('Sichern/Zurueckspielen/Nichts'+katalog[eintrag]['Frage'][0]+BENUTZER+katalog[eintrag]['Frage'][1])
            PASSWORT=benutzer_passwoerter.get(BENUTZER, '')
            if antwort2 in 'sSzZ' and antwort2 not in '':
                child=rsync()
                child.logfile_read = sys.stdout
                if child.expect([' password:', pexpect.EOF],  timeout=3) in [0]:
                    child.sendline(PASSWORT)
                while child.expect([' password:', pexpect.EOF],  timeout=3) in [0]:
                    PASSWORT=sys.stdin.readline()
                    benutzer_passwoerter[BENUTZER]=PASSWORT
                    child.sendline(PASSWORT))
Ich werde wohl noch die Schleife und die letzte Fall-Unterscheidung zusammenfassen. Solange(WHILE) das Child am Leben ist frage den Status ab(IF) und reagiere dementsprechend.
BlackJack

@feldmaus: `eintrag` wird einzig und allein dafür verwendet um aus `katalog` den dazugehörigen Wert zu holen. Da Du aber sowieso über alle Werte aus `katalog` iterierst, ist dieser Umweg über den Schlüssel unnötig. Du kannst auch gleich über `katalog.itervalues()` iterieren.

Komplett gross geschriebene Namen sind per Konvention (PEP8) für Konstanten vorgesehen. `BENUTZER` und `PASSWORT` sind aber keine Konstanten.

Durchnummerieren von Namen ist ein "code smell". Meistens dafür, dass man eigentlich eine Liste verwenden möchte, aber hier eher dafür das zu viel in einer Funktion steckt.

Das so etwas wie ``katalog[eintrag]['Frage'][0]`` und superlange Zeilen die zudem keine Leerzeichen um Operatoren enthalten, schwer lesbar und schwer verständlich sind, hatten wir doch schon mal, oder!?

``in`` ist schon ein netter Operator, aber man muss nicht versuchen *alle* Bedingungen damit auszudrücken. Von den vier Anwendungen in dem Quelltext kann man drei offensichtlicher mit einfachen Vergleichen ausdrücken.

Warum wird für die Passworteingabe `sys.stdin.readline()` anstelle von `raw_input()` verwendet? Sicherer wäre die Eingabe über das `getpass`-Modul. Dann kann niemand die eingegebenen Passwörter am Bildschirm mitlesen.

Am Ende ist eine Klammer zu viel.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

BlackJack hat geschrieben:@feldmaus: `eintrag` wird einzig und allein dafür verwendet um aus `katalog` den dazugehörigen Wert zu holen. Da Du aber sowieso über alle Werte aus `katalog` iterierst, ist dieser Umweg über den Schlüssel unnötig. Du kannst auch gleich über `katalog.itervalues()` iterieren.
Deine Idee mit dem Iterator-Objekt finde ich interessant, doch jedesmal wenn ich drüber nachdenke wie man damit meinen Code vereinfachen/lesbarer machen kann habe ich eher das Gefühl es wird nur schlimmer. Ein Iterator-Objekt hat zu wenig Methoden. Mit next() kann ich nicht alles erschlagen was ich brauche. Und zudem kommt noch, das ich die Ausnahme von dem Iterator behandeln muss(wenn das Ende des iterator erreicht ist), was Zusatz-Code verursacht. Kann man beim Iterator das derzeitige Element ausgeben? Ansonsten müsste ich viel mit Zuweisungen arbeiten und die verlängern meinen Code.

Falls das mit dem Iterator klappt, könnte man damit auch meine langen Zeilen erschlagen.
BlackJack hat geschrieben:Warum wird für die Passworteingabe `sys.stdin.readline()` anstelle von `raw_input()` verwendet? Sicherer wäre die Eingabe über das `getpass`-Modul. Dann kann niemand die eingegebenen Passwörter am Bildschirm mitlesen.
Weil ich nur Daten eingeben will und keine zusätzliche Ausgabe benötige, dass macht das Child schon für mich. Ich hatte eine Fehlermeldung bei raw_input(). Die genaue Fehlermeldung weiß ich nicht mehr, wahrscheinlich hat sich bei den Ausgaben irgendwas gebissen. Ich weiß es nicht mehr :K . Das mit dem Modul getpass finde ich gut und wollte ich eigentlich später ansprechen, aber egal :D

Hier mein vorläufiger Code:

Code: Alles auswählen

    for eintrag in katalog:
        for benutzer in katalog[eintrag]['Benutzer']:
            wasWillstDu=raw_input('Sichern/Zurueckspielen/Nichts'+katalog[eintrag]['Frage'][0]+benutzer+katalog[eintrag]['Frage'][1])
            passwort=benutzer_passwoerter.get(benutzer, '')
            if wasWillstDu in 'sSzZ' and wasWillstDu not in '':
                child=rsync()
                child.logfile_read = sys.stdout
                while child.isalive():
                    statusChild=child.expect([' password:', 'denied', pexpect.TIMEOUT, pexpect.EOF],  timeout=-1)
                    if statusChild == 0:
                        child.sendline(passwort)
                    elif statusChild == 1:
                        passwort=sys.stdin.readline()
                        benutzer_passwoerter[benutzer]=passwort
                        child.sendline(passwort)
Grüße Markus
BlackJack

@feldmaus: Mit dem Iterator solltest Du selbst überhaupt nichts machen ausser darüber iterieren -- mit einer ``for``-Schleife und nicht "zu Fuss".
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

BlackJack hat geschrieben:@feldmaus: Mit dem Iterator solltest Du selbst überhaupt nichts machen ausser darüber iterieren -- mit einer ``for``-Schleife und nicht "zu Fuss".
Ich werde mal ein wenig konkreter, aber nicht zu viel. Hier der Code

Code: Alles auswählen

    iterEintraege=katalog.itervalues()
    for benutzer in iterEintraege.next()['Benutzer']:
        wasWillstDu=raw_input('Sichern/Zurueckspielen/Nichts'+katalog[eintrag]['Frage'][0]+benutzer+katalog[eintrag]['Frage'][1])
        passwort=benutzer_passwoerter.get(benutzer, '')
        if wasWillstDu in 'sSzZ' and wasWillstDu not in '':
            child=rsync()
            child.logfile_read = sys.stdout
            while child.isalive():
                statusChild=child.expect([' password:', 'denied', pexpect.TIMEOUT, pexpect.EOF],  timeout=-1)
                if statusChild == 0:
                    child.sendline(passwort)
                elif statusChild == 1:
                    passwort=sys.stdin.readline()
                    benutzer_passwoerter[benutzer]=passwort
                    child.sendline(passwort)
Ich habe jetzt zwar eine Schleife gespart, aber der Code funktioniert nicht, weil ich in der for-Anweisung keine Zuweisung von dem next() Objekt machen kann. Somit steht mir dieses Objekt auch weiter unten nicht zur Verfügung. Hast Du eine Idee wie ich eine Zuweisung da rein bekomme, also so ähnlich wie

Code: Alles auswählen

for benutzer in eintrag=iterEintraege.next()['Benutzer']:
Und irgendwie müsste ich noch eine Exception einbauen, für den Fall das der Iterator zu Ende ist.
BlackJack

@feldmaus: Natürlich funktioniert das so nicht. Nach dem ``in`` in einer ``for``-Schleife muss ein iterierbares Objekt stehen. Zum Beispiel ein Iterator. Über die Elemente dieses Iterators geht die ``for``-Schleife dann. Du musst dafür weder die `next()`-Methode aufrufen noch die `StopIteration` behandeln. Das macht alles die ``for``-Schleife intern. Die einzelnen Elemente werden nacheinander an den Namen nach dem ``for`` gebunden. Das sind Grundlagen; so funktioniert *jede* ``for``-Schleife in Python.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

@BlackJack
Sag das doch gleich :mrgreen:

Code: Alles auswählen

    for eintrag in katalog.itervalues():
        for benutzer in eintrag['Benutzer']:
            wasWillstDu=raw_input('(S)ichern/(Z)urueckspielen/(N)ichts/(A)bbrechen'+eintrag['Frage'][0]+benutzer+eintrag['Frage'][1]+' ? (s/z/n/a) ')
            passwort=benutzer_passwoerter.get(benutzer, '')
            if wasWillstDu in 'sSzZ' and wasWillstDu not in '':
                child=rsync()
                child.logfile_read = sys.stdout
                while child.isalive():
                    statusChild=child.expect([' password:', 'denied', pexpect.TIMEOUT, pexpect.EOF],  timeout=-1)
                    if statusChild == 0:
                        child.sendline(passwort)
                    elif statusChild == 1:
                        passwort=getpass.getpass('')
#                        passwort=sys.stdin.readline()
                        benutzer_passwoerter[benutzer]=passwort
                        child.sendline(passwort)
            elif wasWillstDu in 'aAqQ' and wasWillstDu not in '':
                sys.exit(0)
EDIT: Habe das getpass Modul nochmal nachgetragen.
Zuletzt geändert von feldmaus am Freitag 29. April 2011, 08:59, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich kenne die Struktur von ``katalog`` nicht, aber vermutlich suchst du so etwas wie:

Code: Alles auswählen

for eintrag in katalog.values():
    benutzer = eintrag['Benutzer']
    [...]
EDIT: Anscheinend hast du schon gefunden, was du wolltest.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Das getpass Modul macht nicht das was es soll. Das eingegebene Passwort wird jedes mal an die Variable <passwort> angehängt. Also z.b. gebe ich zu erst 943jfn ein dann sj38sks und dann dk32k5, dann würde beim dritten Durchgang die Variable passwort wie folgt lauten 943jfnsj38sksdk32k5

Hat da Jemand einen Tipp für mich?

EDIT: Ich wollte das Programm gerne im Terminal aber grafisch in Richtung ncurses aufpeppen und vielleicht noch eine XML Datenbank dazu. Gibt es ein Modul womit ich solche eine Terminal/Konsolen :mrgreen: -Grafik bewerkstelligen kann?

EDIT2: Hier ein Link zu curses unter Python http://de.wikibooks.org/wiki/Python_unter_Linux:_Curses
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

feldmaus hat geschrieben:Das getpass Modul macht nicht das was es soll. Das eingegebene Passwort wird jedes mal an die Variable <passwort> angehängt. Also z.b. gebe ich zu erst 943jfn ein dann sj38sks und dann dk32k5, dann würde beim dritten Durchgang die Variable passwort wie folgt lauten 943jfnsj38sksdk32k5
Habs ausprobiert, kann ich nicht nachvollziehen. Bei mir funktionierts wie erwartet.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich kann das Problem auch nicht nachvollziehen, bei mir funktionierts.
Das Leben ist wie ein Tennisball.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Ich habe es gerade nochmal getestet. Dieses Verhalten scheint er nur in der Entwicklungsumgebung von Eric4 (Version 4.4.12) zu haben, aber nicht in der Konsole. Keine Ahnung warum.

Meine nächste Aufgabe wäre das man das Backup auch für andere Benutzer ausführen kann, egal von welchem Rechner, also remote nach remote oder lokal nach remote, am liebsten auch innerhalb eines remote Rechners. Dann wären mehrere Passwort Eingaben erforderlich. Schön wäre auch eine Erstellung einer System-Doku. Ich stehe ja nicht so auf koopieren von System-Dateien, sondern viel mehr auf System-Doku.

Hier nochmal der Link http://pastebin.com/9NfjtMup

Grüße Markus
Antworten