scp und wildcards
MudGuard
- programmiertechnik
1 Henryk Plötz
Hi,
ich will Files von einem Rechner auf den anderen mit scp kopieren.
Soweit ja kein Problem.
In dem Verzeichnis, aus dem ich die Dateien holen will, liegen viele Dateien mit verschiedensten Namen - ich brauch davon nur solche, die mit Au und mit fr anfangen.
An sich auch noch kein Problem:
scp -p -C user@server:/pfad/Au* user@server:/pfad/fr* .
Leider werde ich jetzt aber zweimal nach dem Passwort gefragt - einmal für die Au* und einmal für die fr*.
Was ich also gerne hätte, wäre sowas wie
scp -p -C user@server:/pfad/(Au*|fr*) .
(hier mal als Regex ausgedrückt: Au* oder fr* )
Funktioniert aber so natürlich nicht.
Gibt es eine andere Syntax, mit der ich meinen Wunsch erfüllt bekomme?
Da ich das ganze für 15 verschiedene Server machen muß, geht es also nicht darum, das Paßwort nur einmal statt zweimal einzutippen, es geht um 15 statt 30 Mal. Und das fünfmal die Woche ...
Default-Shell des Users ist auf allen Kisten die bash.
cu,
Andreas
Moin,
Was ich also gerne hätte, wäre sowas wie
scp -p -C user@server:/pfad/(Au*|fr*) .
Die übliche Shellsyntax dafür ist {Au,fr}*
Da ich das ganze für 15 verschiedene Server machen muß, geht es also nicht darum, das Paßwort nur einmal statt zweimal einzutippen, es geht um 15 statt 30 Mal. Und das fünfmal die Woche ...
Für die Zukunft: Schau dir Public-Key-Authentisierung an. (Wahlweise mit Schlüssel ohne Passphrase oder mit ssh-agent.) Das macht vieles _viel_ leichter.
Hi,
Was ich also gerne hätte, wäre sowas wie
scp -p -C user@server:/pfad/(Au*|fr*) .
Die übliche Shellsyntax dafür ist {Au,fr}*
Danke - werd ich gleich morgen früh ausprobieren - war bis eben zum Stammtisch ...
Für die Zukunft: Schau dir Public-Key-Authentisierung an. (Wahlweise mit Schlüssel ohne Passphrase oder mit ssh-agent.) Das macht vieles _viel_ leichter.
Es ist expliziter Wunsch der IT-Leitung, daß keine Public-Key-Authentisierung zwischen den Maschinen eingesetzt wird - sollte jemand in einen Rechner eindringen können, sollen nicht gleich die Scheunentore zu den anderen offenstehen ...
cu,
Andreas
Hi,
Es ist expliziter Wunsch der IT-Leitung, daß keine Public-Key-Authentisierung zwischen den Maschinen eingesetzt wird - sollte jemand in einen Rechner eindringen können, sollen nicht gleich die Scheunentore zu den anderen offenstehen ...
Public-Keys können ebenfalls mit Passwörtern geschützt werden, und sind deshalb sicherer, weil die Passwörter nicht übers Netzwerk übertragen werden müssen. Wird der Key entwendet ist er ohne Passwort nutzlos.
Schöne Grüße
Julian
Hi,
Public-Keys können ebenfalls mit Passwörtern geschützt werden, und sind deshalb sicherer, weil die Passwörter nicht übers Netzwerk übertragen werden müssen. Wird der Key entwendet ist er ohne Passwort nutzlos.
Oh, da hab ich wohl was falsch verstanden (kenn mich mit dem Netzwerkskram nicht wirklich aus) - ich weiß nur, daß zwischen zwei Servern sowas mit Public Keys eingerichtet wurde, da geht es (beabsichtigt) ohne Paßwort.
cu,
Andreas
Moin!
Es ist expliziter Wunsch der IT-Leitung, daß keine Public-Key-Authentisierung zwischen den Maschinen eingesetzt wird - sollte jemand in einen Rechner eindringen können, sollen nicht gleich die Scheunentore zu den anderen offenstehen ...
Muß ja auch nicht. Ich habe lokal auf meinem Rechner meine Keys, und erlaube den Shells zu meinem lokalen Server, dass die Keyauthentifizierung weiterleitet wird. So kann ich mich direkt auf anderen Servern einloggen, oder über die Zwischenstation meines lokalen Servers gehen - ohne dass der lokale Server meine Keys kennen würde.
Sehr praktisch für alles, was SSH, SCP, SFTP oder RSYNC heißt. :)
- Sven Rautenberg
Hi,
Muß ja auch nicht. Ich habe lokal auf meinem Rechner meine Keys, und erlaube den Shells zu meinem lokalen Server, dass die Keyauthentifizierung weiterleitet wird. So kann ich mich direkt auf anderen Servern einloggen, oder über die Zwischenstation meines lokalen Servers gehen - ohne dass der lokale Server meine Keys kennen würde.
Irgendwie sind da auch Keys im Spiel - ich hab mit der Einrichtung der Sicherheitsmaßnahmen nichts zu tun, ich "leide" nur unter den Auswirkungen ;-)
cu,
Andreas
Hi,
Was ich also gerne hätte, wäre sowas wie
scp -p -C user@server:/pfad/(Au*|fr*) .
Die übliche Shellsyntax dafür ist {Au,fr}*
Getestet und halbwegs für gut befunden.
Es werden mit
user@server:/pfad/{Au,fr}*
zwar alle Files erfaßt, die ich haben will - aber die Paßwortfrage kommt dennoch nach den Au* Dateien ein zweites Mal.
cu,
Andreas
Hallo Andreas,
Was ich also gerne hätte, wäre sowas wie
scp -p -C user@server:/pfad/(Au*|fr*) .
Die übliche Shellsyntax dafür ist {Au,fr}*Getestet und halbwegs für gut befunden.
Es werden mit
user@server:/pfad/{Au,fr}*
zwar alle Files erfaßt, die ich haben will - aber die Paßwortfrage kommt dennoch nach den Au* Dateien ein zweites Mal.
Das Problem ist, dass das {Au,fr} schon bei Deiner Shell auf Deinem Rechner ersetzt wird und *nicht* erst auf der Shell des Rechners, von dem Du kopieren willst. Der einzige Grund, warum das * nicht ersetzt wird, ist, dass die Shell auf Deinem Rechner keine Verzeichnis »user@server:« im aktuellen Verzeichnis findet und somit keine Autocompletion macht. Kannst Du auch mal ausprobieren: »echo BLOEDSINN*« ergibt »BLOEDSINN*«, »echo .*« gibt mindestens ». ..« und evtl. andere noch vorhandene Datein im aktuellen Verzeichnis, die mit einem . anfangen. Das ganze geht sogar so weit, dass wenn Du ein Verzeichnis »user@sever:« hättest, das ein Verzeichnis »pfad« enthielten, das bereits Dateien, die mit »Au« und »fr« anfangen würden, enthielten, dann würde die _komplette_ Substitution auf Deinem Rechner bereits durchegeführt und er würde nur bestimmte Dateien - sofern sie überhaupt auf dem fremden Server vorhanden wären, kopieren. Da sich wohl niemand Verzeichnisse der Form »user@server:« anlegt, kracht das bei scp wohl nie. Die {}-Completion dagegen kann ja durchaus von der Shell ersetzt werden, ohne, dass sie sich Dateien anschaut, daher wird das auch gemacht. Im Endeffekt bekommt scp bei der {Au,fr}-Angabe die *identischen* Parameter mit, wie bei Deinem ersten Befehl, Du schreibst nur weniger.
Die Lösung des Problems besteht darin, die komplette Substitution durch die Remote-Shell durchführen zu lassen. Dies erreichst Du, indem Du der lokalen Shell verweigerst, die Substitution durchzuführen. Der Befehl sollte also folglich lauten (die Parameter habe ich von Dir übernommen):
scp -p -C "user@server:/pfad/{Au,fr}*" .
Damit musst Du die Passwortabfrage nur einmal eingeben.
Viele Grüße,
Christian
Hi,
Das Problem ist, dass das {Au,fr} schon bei Deiner Shell auf Deinem Rechner ersetzt wird und *nicht* erst auf der Shell des Rechners, von dem Du kopieren willst. Der einzige Grund, warum das * nicht ersetzt wird, ist, dass die Shell auf Deinem Rechner keine Verzeichnis »user@server:« im aktuellen Verzeichnis findet und somit keine Autocompletion macht. Kannst Du auch mal ausprobieren: »echo BLOEDSINN*« ergibt »BLOEDSINN*«, »echo .*« gibt mindestens ». ..« und evtl. andere noch vorhandene Datein im aktuellen Verzeichnis, die mit einem . anfangen. Das ganze geht sogar so weit, dass wenn Du ein Verzeichnis »user@sever:« hättest, das ein Verzeichnis »pfad« enthielten, das bereits Dateien, die mit »Au« und »fr« anfangen würden, enthielten, dann würde die _komplette_ Substitution auf Deinem Rechner bereits durchegeführt und er würde nur bestimmte Dateien - sofern sie überhaupt auf dem fremden Server vorhanden wären, kopieren. Da sich wohl niemand Verzeichnisse der Form »user@server:« anlegt, kracht das bei scp wohl nie. Die {}-Completion dagegen kann ja durchaus von der Shell ersetzt werden, ohne, dass sie sich Dateien anschaut, daher wird das auch gemacht. Im Endeffekt bekommt scp bei der {Au,fr}-Angabe die *identischen* Parameter mit, wie bei Deinem ersten Befehl, Du schreibst nur weniger.
Das hab ich mir schon fast gedacht, daß das lokal passiert ...
Die Lösung des Problems besteht darin, die komplette Substitution durch die Remote-Shell durchführen zu lassen. Dies erreichst Du, indem Du der lokalen Shell verweigerst, die Substitution durchzuführen. Der Befehl sollte also folglich lauten (die Parameter habe ich von Dir übernommen):
scp -p -C "user@server:/pfad/{Au,fr}*" .
Getestet und für sehr gut befunden.
Dankeschön!
Jetzt wünsch ich mir nur noch ein Feature, mit dem ich die Auswahl auf Dateien neuer als ein vorgegebenes Datum einschränken könnte (VOR der Übertragung - danach ist es kein Problem ...)
Leider ist scp andersrum (also vom Remote-Rechner auf den lokalen) gesperrt ...
cu,
Andreas
Hallo Andreas,
Jetzt wünsch ich mir nur noch ein Feature, mit dem ich die Auswahl auf Dateien neuer als ein vorgegebenes Datum einschränken könnte (VOR der Übertragung - danach ist es kein Problem ...)
Leider ist scp andersrum (also vom Remote-Rechner auf den lokalen) gesperrt ...
Warum genau willst Du die Auswahl einschränken? Nur, um neuere Dateien zu übertragen und alte nicht doppelt? Dann könntest Du - falls auf *beiden* Rechnern rsync installiert ist - Dir mal das Tool ansehen. Das kann nämlich Verzeichnisbäume synchronisieren - auch über SSH. Das kopiert dann nur die neueren Dateien bzw. wenn sich eine Datei geändert hat nur die Änderungen rüber. Wenn die Aufgabenstellung komplizierter ist (z.B. Du lokal keine vollständige Kopie aller Dateien auf dem Server behalten kannst), funktioniert rsync natürlich nicht mehr.
Viele Grüße,
Christian
Hi,
Warum genau willst Du die Auswahl einschränken? Nur, um neuere Dateien zu übertragen und alte nicht doppelt?
Richtig. Es geht vor allem darum, den Vorgang zu beschleunigen.
20 Files a 10MB von einem Rechner zu übertragen dauert halt wesentlich länger als nur die 3 oder 4 wirklich benötigten zu holen.
Das ganze dann noch mit Faktor 15 ...
Da für jeden der 15 Server das Paßwort eingegeben werden muß (da führt kein Weg dran vorbei), ist es natürlich lästig, wenn man das Script ewig "beaufsichtigen" muß - je kürzer die Wartezeiten zwischen den Paßworteingaben, desto besser.
Ist halt irgendwie doof, erst 20 Dateien zu übertragen, um dann 15 oder mehr davon sofort wieder zu löschen ...
Wenn die Aufgabenstellung komplizierter ist (z.B. Du lokal keine vollständige Kopie aller Dateien auf dem Server behalten kannst),
ist aus Platzgründen nicht möglich, die Dateien vollständig zu erhalten ...
cu,
Andreas
Hallo Andreas,
Warum genau willst Du die Auswahl einschränken? Nur, um neuere Dateien zu übertragen und alte nicht doppelt?
Richtig. Es geht vor allem darum, den Vorgang zu beschleunigen.
20 Files a 10MB von einem Rechner zu übertragen dauert halt wesentlich länger als nur die 3 oder 4 wirklich benötigten zu holen.
Das ganze dann noch mit Faktor 15 ...
Da für jeden der 15 Server das Paßwort eingegeben werden muß (da führt kein Weg dran vorbei), ist es natürlich lästig, wenn man das Script ewig "beaufsichtigen" muß - je kürzer die Wartezeiten zwischen den Paßworteingaben, desto besser.
Mich hat das jetzt nicht losgelassen und ich hab ne Lösungsmöglichkeit gefunden. Du kannst nämlich Backtick-Angaben an die fremde Shell weiterleiten. Beispiel:
scp "christian@andromeda:\
find /home/christian/test -newer /home/christian/test/a -a -type f`" .`
Ich hatte in /home/christian/test auf meinem Rechner andromeda drei Dateien angelegt: a, b und c in genau dieser Reihenfolge im Abstand von ein paar Minuten - a war also die älteste etc. Wenn ich auf andromeda selbst jetzt
find /home/christian/test -newer /home/christian/test/a -a -type f
laufen lasse, dann findet er mir alle Dateien, die neuer sind, als /home/christian/test/a (das -a -type f mache ich, damit er das Verzeichnis /home/christian/test selbst nicht zurückgibt, das ja zum gleichen Zeitpunkt, in dem die letzte Datei darin erstellt wurde, zuletzt geändert wurde) - in dem Fall also /home/christian/test/b und /home/christian/test/c.
Der Trick ist jetzt, dass ich das ganze an die fremde Shell übergeben kann - allerdings müssen die Backticks maskiert sein (`), da diese sonst bereits auf der lokalen Shell ausgeführt werden.
Einziger Haken: Durch die Backticks sind Dateien/Verzeichnisse mit Leerzeichen nicht möglich zu behandeln (er denkt dann, es wären 2 Dateien), ich hab auf Anhieb leider keinen glorreichen Einfall gehabt, wie man das in dem Fall (da geht's ja nur mit Backticks) umgehen könnte.
Viele Grüße,
Christian
Hi,
Mich hat das jetzt nicht losgelassen und ich hab ne Lösungsmöglichkeit gefunden. Du kannst nämlich Backtick-Angaben an die fremde Shell weiterleiten. Beispiel:
scp "christian@andromeda:\
find /home/christian/test -newer /home/christian/test/a -a -type f`" .`
Klingt interessant, werd ich mir morgen im Büro mal angucken.
Wenn ich das richtig sehe, geht der Zeitvergleich gegen eine Datei auf dem remote-System - ich hab aber ein Datum als Parameter.
Aber die Idee mit find ist gut - wobei ich -newer <file> durch -mtime -1 bzw. montags -mtime -3 ersetzen werde.
Schade, daß da keine Bruchteile erlaubt sind, sondern nur ganze 24h-Perioden.
Ich kann das aber von hier nicht testen ==> morgen im Büro.
Einziger Haken: Durch die Backticks sind Dateien/Verzeichnisse mit Leerzeichen nicht möglich zu behandeln
Das ist kein Problem - die betroffenen Dateien haben keine Leerzeichen im Namen.
(m.E. gehören diejenigen, die auf die Idee gekommen sind, Leerzeichen in Dateinamen zuzulassen, gevierteilt).
Aber nur mal so als Idee - wenn innerhalb der Backticks ein " steht, müßte das doch als normales " in der remote-Shell ankommen, und damit müßte man den Filenamen in "" einschließen können (ungetestet)
Danke jedenfalls für Deine Bemühungen!
cu,
Andreas
Hallo Andreas,
Aber nur mal so als Idee - wenn innerhalb der Backticks ein " steht, müßte das doch als normales " in der remote-Shell ankommen, und damit müßte man den Filenamen in "" einschließen können (ungetestet)
Das Problem ist, dass dann *alle* Dateinamen in " eingeschlossen werden, d.h. wenn find die Dateien »Datei1« und »Datei 2« liefert, führt das einschließen in " dazu, dass er versucht, "Datei1 Datei 2" zu kopieren - und die gibt's natürlich nicht. Ich habe auch schon versucht, alle Leerzeichen durch \ gefolgt von dem Leerzeichen zu ersetzen - das Problem ist, dass das \ bei der *Ausgabe* von Backticks anscheinend nicht mehr evaluiert wird. Ferner habe ich probiert um jedes Ergebnis von find Anführungszeichen zu setzen - was auch nicht funktioniert, da diese auch nicht mehr evaluiert werden.
Viele Grüße,
Christian
Hi,
Das Problem ist, dass dann *alle* Dateinamen in " eingeschlossen werden,
Ups, hab übersehen, daß der Filename ja nicht dasteht, sondern erst vom find erzeugt wird.
Wie sieht es aus, wenn man anstelle der default-Ausgabe per -exec echo "{}" ; verwendet?
Bzw., da das ganze ja nochmal gequotet ist, mit -exec echo "{}" \;
Ferner habe ich probiert um jedes Ergebnis von find Anführungszeichen zu setzen - was auch nicht funktioniert, da diese auch nicht mehr evaluiert werden.
Meintest Du damit sowas wie mein -exec?
cu,
Andreas
Hallo Andreas,
Wie sieht es aus, wenn man anstelle der default-Ausgabe per -exec echo "{}" ; verwendet?
Bzw., da das ganze ja nochmal gequotet ist, mit -exec echo "{}" \;Ferner habe ich probiert um jedes Ergebnis von find Anführungszeichen zu setzen - was auch nicht funktioniert, da diese auch nicht mehr evaluiert werden.
Meintest Du damit sowas wie mein -exec?
Ich hab's zwar auf andere Weise gemacht, aber bei Deinem Exec passiert genau das gleiche. Ein
ls find . -newer b -a -type f -exec echo \"{}\" \\;
führt zu
ls: "./c": No such file or directory
ls: "./bla: No such file or directory
ls: blub": No such file or directory
Die Anführungszeichen werden somit also Teil des Dateinamens.
Viele Grüße,
Christian
Hi,
scp "christian@andromeda:\
find /home/christian/test -newer /home/christian/test/a -a -type f`" .`
so, hab's jetzt zum Laufen gebracht.
find wollte irgendwie nicht mit -name '{Au,fr}*' - da kam immer eine leere Menge ==> grep
scp "user@server:`find /pfad -mtime -4 -type f | grep 'Au|fr'`" .
(plus minus einige Quotes und Escapes - das ganze steckt zusätzlich noch in einem Perl-Script-String, und einige der Teile kommen noch aus Variablen ...)
cu,
Andreas
Hallo Andreas,
so, hab's jetzt zum Laufen gebracht.
find wollte irgendwie nicht mit -name '{Au,fr}*' - da kam immer eine leere Menge ==> grepscp "user@server:`find /pfad -mtime -4 -type f | grep 'Au|fr'`" .
Damit find das macht, geht folgendes:
find /pfad -mtime 4 -a -type f -a ( -name 'Au*' -o -name 'fr*' )
(+ evtl. weitere Backslashes o.ä., falls Du's in die Backticks kopierst)
Viele Grüße,
Christian
Hi,
scp "user@server:`find /pfad -mtime -4 -type f | grep 'Au|fr'`" .
Damit find das macht, geht folgendes:find /pfad -mtime 4 -a -type f -a ( -name 'Au*' -o -name 'fr*' )
Ok - aber nach dem Motto "never run a changing system" (o.ä.) werd ich's so lassen wie es jetzt läuft.
Schnell genug ist es mir, das bißchen Shellzeugs fällt im Vergleich zu den Übertragungszeiten nicht ins Gewicht ...
cu,
Andreas
Moin,
Da für jeden der 15 Server das Paßwort eingegeben werden muß (da führt kein Weg dran vorbei)
Doch führt. Gegen public key auf den Servern und private key (mit Passphrase) auf deinem lokalen Rechner/Laptop spricht sicherheitstechnisch genau gar nichts, es ist Passwortauthentisierung sogar vorzuziehen. Hier nochmal in Farbe und Bunt: http://www.unixwiz.net/techtips/ssh-agent-forwarding.html
Wenn man allerdings unbedingt darauf besteht dem Benutzer möglichst viele Steine in den Weg zu legen damit der auch ja kreative Wege findet diese zu umgehen und dabei die Sicherheit zu schwächen ... bittesehr, auch das ist möglich. Mit Trick 17, 18 und 19 zusammen kann man SSH dazu bringen das Passwort aus einem Skript zu akzeptieren, damit man es nicht selbst eingeben muss (ursprünglich habe ich das entwickelt um skriptgesteuert auf einen abgespeckten dropbear zu kommen der kein pubkey-auth kann):
Der Schlüssel ist die Umgebungsvariable SSH_ASKPASS, damit kann man ein Kommando angeben welches ssh benutzen soll um das Passwort einzuholen, falls es kein tty hat. Der erste Schritt ist also einfach: Erstelle ein Skript welches dein Passwort ausgibt:
#!/bin/bash
echo passwort
Eigentlich[tm] solltest du jetzt mit SSH_ASKPASS=/pfad/zu/deinem/skript ssh benutzer@host
(bash-syntax) ssh oder scp machen können, ohne ein Passwort einzugeben. Die Realität ist leider komplizierter. Ssh verwendet SSH_ASKPASS offenbar wirklich nur, wenn kein TTY aber dafür ein X (DISPLAY ist gesetzt) zur Verfügung steht. Mir ist keine wirklich schöne Lösung eingefallen, um dem ssh das TTY wegzunehmen, aber dafür eine etwas weniger schöne: Undzwar kann man, wenn man sich mit ssh irgendwo einloggt sich aussuchen ob ein TTY alloziiert werden soll oder nicht. Also machst du einfach ssh auf deine lokale Kiste (da wirst du pubkey-auth ja wohl noch hinkriegen) mit dem Parameter -T und rufst dann obiges Kommando auf (DISPLAY setzen nicht vergessen). Ungefähr so:
ssh -T localhost "/bin/bash -c 'DISPLAY=foo SSH_ASKPASS=/pfad/zu/deinem/skript ssh benutzer@host'"
Getestet und für hässlich befunden, geht aber.