¿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 1
es defectuoso y no se puede solucionar de forma fiable. Un reemplazo confiable estándar es find
y/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 cp
no 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 cp
se detenga el análisis de opciones, por lo que, por ejemplo, un archivo -R
no 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 scp
en 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 sh
de manera confiableanidar dos find … -exec …
cláusulas. El exterior find
sondea todos los archivos y los suministra uno por uno al interior find
. El interno find
busca todos los archivos más nuevos que el archivo dado, imprimiendo un solo carácter ( a
) para cada archivo más nuevo. wc -c
cuenta estos personajes. Si no hay ninguno, significa que el archivo dado es el modificado más recientemente; Sólo entonces el exterior find
lo imprime.
Hay algunos escenarios en los que el exterior find
puede 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
find
no puede almacenar algunos archivos.
Por esta razón, -quit
como acción final de lo externo find
sería útil (tenga en cuenta que también sería útil con lo interno find
, pero por una razón diferente). Lamentablemente -quit
no es POSIX.
Utilicé -print
( -print0
no 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 -exec
eso para tratar todos los nombres de archivos posibles correctamente; por ejemplo, en lugar de -print
usar:
-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 ssh
ingresar 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 cd
y 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 12322
conduzca a su local sshd
y 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 scp
necesita 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 xargs
y scp
. Tenga en cuenta que analizar lo que -print
produce 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 -print
para 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
sshfs
le 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 sshfs
las 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.