SCP aus der zuletzt geänderten Datei in einem Remote-Verzeichnis

SCP aus der zuletzt geänderten Datei in einem Remote-Verzeichnis

Gibt es einen einfachen Befehl, um die zuletzt geänderte Datei in einem Verzeichnis auf einem Remote-Host per SCP zu senden? Ich kann herausfinden, wie das von lokal auf remote geht ... so etwas wie: scp ``ls -Art | tail -n 1\`` usr@remote:/var/log/yeet Wie kann ich dasselbe tun, aber von remote auf lokal. (Also die zuletzt geänderte Datei von yeet holen und auf den lokalen Host kopieren)

Antwort1

Hier gibt es nur wenige Probleme.

Parsingls

Zunächst einmalsollte nicht analysiert werdenls. Ihr ls -Art | tail -n 1ist fehlerhaft und kann nicht zuverlässig repariert werden. Ein standardmäßiger zuverlässiger Ersatz ist findund/oder das Arbeiten mit nullterminierten Leitungen.

Außerdem gehe ich davon aus, dass Sie die zuletzt geänderte Datei (kein Verzeichnis) direkt im aktuellen Verzeichnis (nicht in einem Unterverzeichnis) benötigen.

Die Fähigkeit, Eingabeelemente in Form einer nullterminierten Liste zu analysieren, wird von POSIX normalerweise nicht benötigt. Wenn Ihre Tools über genügend Optionen verfügen, ist dies ein robuster Ersatz für Ihr ls -Art | tail -n 1:

find . -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2-

Das Ergebnis ist ein nullterminierter Dateiname. Um damit etwas zu tun, müssen Sie es an weiterleiten xargs -0 …, z. B.:

… | xargs -0r cp -t "/target/dir/" --

oder (falls Ihr Gerät cpdies nicht unterstützt -t):

… | xargs -0r -I {} cp -- {} "/target/dir/"

In diesen Befehlen gibt es viele Dinge, die POSIX nicht benötigt (und die daher nicht portierbar sind), einschließlich --der Einstellung, die cpdie Analyse von Optionen stoppt, sodass beispielsweise eine Datei -Rkeine Rekursion auslöst, anstatt kopiert zu werden. Beachten Sie, dass Dateinamen, die unser verlassen, mit Sicherheit find . …mit beginnen und daher getrost weggelassen werden können. Ich habe es nur verwendet, um auf eine gute allgemeine Vorgehensweise beim Umgang mit hinzuweisen . Eine weitere gute Vorgehensweise ist das Anführen von Pfaden: Der Literalwert würde ohne Anführungszeichen funktionieren, aber nachdem Sie dieses Beispiel durch Ihren spezifischen Zielpfad ersetzt haben, benötigen Sie möglicherweise Anführungszeichen, daher verwende ich sie trotzdem..--cp/target/dir/

In Ihrem Fall (von lokal zu remote) würden Sie scpanstelle von verwenden cp. Es kann beim Parsen von Argumenten seine eigenen Macken haben.

Ein POSIX-kompatibler, aber schlecht funktionierender Befehl könnte sein:

find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -print

Es adaptiert einen Ansatz ausdies ist eine andere Antwortzu ersetzen (nicht-POSIX) -maxdepth 1. Es erzeugt shzuverlässigfind … -exec …zwei Klauseln verschachteln. Der äußere Teil findprüft alle Dateien und übergibt sie nacheinander an den inneren Teil find. Der innere Teil findfindet alle Dateien, die neuer sind als die angegebene Datei, und gibt afür jede neuere Datei ein einzelnes Zeichen () aus. wc -czählt diese Zeichen. Wenn keine vorhanden sind, bedeutet dies, dass die angegebene Datei zuletzt geändert wurde; nur dann findgibt der äußere Teil sie aus.

Es gibt einige Szenarien, in denen das äußere Laufwerk findmöglicherweise mehr als eine Datei druckt:

  • es gibt zwei oder mehr Dateien mit derselben „neuesten“ Mtime;
  • Dateien im Verzeichnis werden während der Ausführung des Befehls geändert;
  • das Innere findkann einige Dateien nicht stat.

Aus diesem Grund wäre -quitdie letzte Aktion des Äußeren findnützlich (beachten Sie, dass dies auch bei dem Inneren nützlich wäre find, aber aus einem anderen Grund). Leider -quitist dies kein POSIX.

Ich habe -print( -print0ist nicht POSIX) verwendet. Nicht standardmäßige Dateinamen sind dennoch kein Problem, da Sie die Ausgabe nicht an einen anderen Befehl weiterleiten müssen. Verwenden Sie einfach, -execdas alle möglichen Dateinamen richtig behandelt. Beispielsweise -printverwenden Sie statt:

-exec yet_another_command {} \;

Jetzt wissen Sie, wie Sie die zuletzt geänderte Datei in einem lokalen Verzeichnis finden, ohne sie analysieren zu müssen ls.

Suchen von Dateien auf einem Remote-System

Egal für welchen Ansatz Sie sich entscheiden (einschließlich des fehlerhaften ls … | tail …), Sie müssen den Befehl auf dem Remote-System ausführen (oder nicht, auf diese Ausnahme werde ich später eingehen), um die gewünschte Datei in einem Remote-Verzeichnis zu finden.

Der naheliegendste Ansatz ist, sshin das Remote-System zu wechseln. Im neuen Kontext ist das Remote-System lokal und Ihr lokaler Computer ist remote. (Hier verwende ich den obigen POSIX-kompatiblen Befehl als Beispiel, aber Sie können unseren ersten verwenden, find … | sort -z … | head -z … | cut -z … | xargs -0 …wenn nur das Remote-System alle erforderlichen Optionen unterstützt).

ssh usr@remote
# now on the remote system
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -exec scp {} usr@local:"/target/dir/" \;

Beachten Sie, dass es weitere -s gibt, die durch ersetzt werden müssen, wenn Sie vermeiden cdund verwenden möchten . Mit ist es viel einfacher .find /source/dir …./source/dircd

Ihr lokales System muss per SSH vom Remote-System aus erreichbar sein. Wenn NAT unterwegs ist, können Sie es mit einer Remote-Portweiterleitung umgehen, etwa so:

ssh -R 12322:127.0.0.1:22 usr@remote
# now on the remote system the same cd + find as above
# only the scp part is different 
… -exec scp -P 12322 {} [email protected]:"/target/dir/" \;

Beachten Sie, dass der Remote-Port dadurch 12322zu Ihrem lokalen Port führt sshdund jeder Benutzer des Remote-Systems versuchen könnte, ihn zu missbrauchen. Ein weiteres Problem: Das Remote-System kann so konfiguriert sein, dass Sie einen Port überhaupt nicht weiterleiten können.

Möglicherweise möchten Sie einen einzelnen Befehl auf dem lokalen System ausführen. In diesem Fall ist eine korrekte Anführungszeichensetzung erforderlich, und es wird noch umständlicher:

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -exec scp {} usr@local:"/target/dir/" \;
   '

Ich erwarte jedoch Probleme, wenn die Remote scpnach Ihrem Passwort fragen muss. Aus diesem Grund oder wenn Sie Ihren lokalen Computer nicht ausführen/erreichen können sshd, benötigen Sie möglicherweise einen anderen Ansatz.

Dieser lokale Befehl druckt den gewünschten Dateinamen, der vom Remote-System abgerufen wurde:

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -print
   '

Sie können es verwenden mitlokalTools wie xargsund scp. Beachten Sie, dass das Parsen von -printnur geringfügig besser ist als das Parsen von ls. Verwenden Sie -print0(nicht POSIX, möglicherweise nicht verfügbar) oder -exec printf "%s\0" {} \;(sollte funktionieren) anstelle von -print, um den gewünschten Dateinamen als nullterminierten String zu erhalten. Jetzt liegt es an Ihnen, was Sie damit auf der lokalen Seite machen. Dies ist nützlich, wenn Sie einen POSIX-kompatiblen Remote-Befehl benötigen, die Tools in Ihrem lokalen System jedoch viele Optionen bieten.

Bemerkenswerte Ausnahme:sshfs

sshfsermöglicht Ihnen die Montage usr@remote:"/source/dir/"als /local/path/. Siehediese Antwort von mir, ich werde mich nicht wiederholen, um auf alle Details einzugehen. In Ihrem Fall sieht das (lokale) Verfahren mit umfangreichen (nicht auf POSIX beschränkten) Tools wie folgt aus:

sshfs usr@remote:"/source/dir/" "/local/path/"
find "/local/path/" -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2- |
   xargs -0r cp -t "/target/dir/" --
fusermount -u "/local/path/"

Das ist großartig. Alles, was Sie tun, tun Sie mitlokalTools. Wenn Sie die Tools nur auf der Remote-Seite verwenden können sshfs, spielen ihre verfügbaren Optionen keine Rolle mehr. Es spielt auch keine Rolle, ob Sie Ihr lokales System von außen erreichen können. Und die Methode ist dieselbe: Remote zu lokal oder lokal zu Remote, es spielt keine Rolle.

verwandte Informationen