SCP desactiva el archivo modificado más recientemente en un directorio remoto

SCP desactiva el archivo modificado más recientemente en un directorio remoto

¿Existe un comando simple para SCP el archivo modificado más recientemente en un directorio en un host remoto? Puedo descubrir cómo hacerlo de local a remoto... algo como: scp ``ls -Art | tail -n 1\`` usr@remote:/var/log/yeet ¿Cómo puedo hacer lo mismo pero de remoto a local? (Así que obtenga el archivo modificado más recientemente de yeet y cópielo en el host local)

Respuesta1

Hay pocos problemas aquí.

Analizandols

Primero que nada tuno debería analizarls. Su problema ls -Art | tail -n 1es defectuoso y no se puede solucionar de forma fiable. Un reemplazo confiable estándar es findy/o trabajar con líneas terminadas en nulo.

Además, supongo que necesita el archivo modificado más recientemente (no un directorio) directamente en el directorio actual (no en un subdirectorio).

POSIX generalmente no requiere la capacidad de analizar elementos de entrada en forma de lista terminada en nulo. Si sus herramientas son lo suficientemente ricas en opciones, este es un reemplazo sólido para su ls -Art | tail -n 1:

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

Produce el resultado como un nombre de archivo terminado en nulo. Para hacer algo con él necesitas canalizarlo a xargs -0 …, por ejemplo:

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

o (si cpno es compatible -t):

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

En estos comandos hay muchas cosas que POSIX no requiere (por lo tanto, no son portátiles), incluido --lo que hace que cpse detenga el análisis de opciones, por lo que, por ejemplo, un archivo -Rno activará la recursividad en lugar de copiarse. Tenga en cuenta que los nombres de archivos que salen de nuestro find . …comienzo con .seguridad, por lo que --se pueden omitir con seguridad. Lo usé solo para señalar una buena práctica general al tratar con cp. Otra buena práctica es citar rutas: el literal /target/dir/funcionaría sin las comillas, pero después de reemplazar este ejemplo con su ruta de destino específica, es posible que necesite comillas, así que las usaré de todos modos.

En su caso (de local a remoto), usaría scpen lugar de cp. Puede tener sus propias peculiaridades al analizar argumentos.

Un comando compatible con POSIX pero de bajo rendimiento puede ser:

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

Adapta un enfoque deesta otra respuestapara sustituir (no POSIX) -maxdepth 1. Se genera shde manera confiableanidar dos find … -exec …cláusulas. El exterior findsondea todos los archivos y los suministra uno por uno al interior find. El interno findbusca todos los archivos más nuevos que el archivo dado, imprimiendo un solo carácter ( a) para cada archivo más nuevo. wc -ccuenta estos personajes. Si no hay ninguno, significa que el archivo dado es el modificado más recientemente; Sólo entonces el exterior findlo imprime.

Hay algunos escenarios en los que el exterior findpuede imprimir más de un archivo:

  • hay dos o más archivos con el mismo mtime "más nuevo";
  • los archivos del directorio se modifican mientras se ejecuta el comando;
  • el interno findno puede almacenar algunos archivos.

Por esta razón, -quitcomo acción final de lo externo findsería útil (tenga en cuenta que también sería útil con lo interno find, pero por una razón diferente). Lamentablemente -quitno es POSIX.

Utilicé -print( -print0no es POSIX), pero los nombres de archivos no estándar no son un problema porque no es necesario canalizar la salida a otro comando. Simplemente use -execeso para tratar todos los nombres de archivos posibles correctamente; por ejemplo, en lugar de -printusar:

-exec yet_another_command {} \;

Ahora ya sabe cómo encontrar el archivo modificado más recientemente en un directorio local sin analizarlo ls.

Encontrar archivos en un sistema remoto

Cualquiera que sea el enfoque que elija (incluido el defectuoso ls … | tail …), debe ejecutar el comando en el sistema remoto (o no, abordaré esta excepción más adelante) para encontrar el archivo deseado en un directorio remoto.

El enfoque más obvio es sshingresar al sistema remoto. En el nuevo contexto, el sistema remoto es local y su computadora local es remota. (Aquí estoy usando el comando anterior compatible con POSIX como ejemplo, pero puede usar el primero find … | sort -z … | head -z … | cut -z … | xargs -0 …si solo el sistema remoto admite todas las opciones requeridas).

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/" \;

Tenga en cuenta que si desea evitarlo cdy usarlo find /source/dir …, hay más .-s que deben reemplazarse por /source/dir. Es mucho más fácil con cd.

Necesita que su sistema local esté disponible vía SSH desde el remoto. Si hay NAT en camino, puedes evitarlo con un reenvío de puerto remoto, algo como esto:

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/" \;

Tenga en cuenta que hace que el puerto remoto 12322conduzca a su local sshdy cualquier usuario del sistema remoto puede intentar hacer un mal uso de él. Otro problema: el sistema remoto puede estar configurado para no permitirle reenviar un puerto en primer lugar.

Es posible que desee invocar un único comando en el sistema local. En este caso se requiere una cotización adecuada y se vuelve aún más engorroso:

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/" \;
   '

Sin embargo , espero problemas si el control remoto scpnecesita solicitar su contraseña. Por este motivo, o si no puede ejecutar o llegar a su local sshd, es posible que necesite otro enfoque.

Este comando local imprimirá el nombre de archivo deseado obtenido del sistema remoto:

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
   '

Puedes usarlo conlocalherramientas como xargsy scp. Tenga en cuenta que analizar lo que -printproduce es sólo ligeramente mejor que analizar ls. Utilice -print0(no POSIX, puede no estar disponible) o -exec printf "%s\0" {} \;(debería funcionar) en lugar de -printpara obtener el nombre de archivo deseado como una cadena terminada en nulo. Ahora depende de ti qué harás con él en el lado local. Esto es útil si necesita tener un comando remoto compatible con POSIX pero las herramientas de su sistema local son ricas en opciones.

Excepción notable:sshfs

sshfsle permite montar usr@remote:"/source/dir/"como /local/path/. Veresta respuesta mía, No me repetiré para cubrir todos los detalles. En su caso, el procedimiento (local) con herramientas ricas (no limitadas a POSIX) es como:

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/"

Esto es genial. Todo lo que haces lo haces conlocalherramientas. Si tan solo pudieras usar sshfslas herramientas en el lado remoto y sus opciones disponibles ya no importan. Tampoco importa si puedes acceder a tu sistema local desde el exterior. Y el método es el mismo: remoto a local o local a remoto, no importa.

información relacionada