从远程同步某个模式的最新两个文件

从远程同步某个模式的最新两个文件

我想在不同环境中的两台服务器之间同步特定模式的最新两个文件:

drwxrwxr-x 2 transfer transfer          4096 28. Nov 13:05 .
drwxr-xr-x 7 transfer transfer          4096 28. Nov 13:05 ..
-rw-rw-r-- 1 transfer transfer   11151643678 28. Nov 12:46 test_28-11-2023.dmp.gz
-rw-rw-r-- 1 transfer transfer         29789 28. Nov 13:04 test_28-11-2023.log
-rw-r--r-- 1 transfer transfer   10770251760 28. Nov 13:00 test_anonym_19-11-2023.dmp.gz
-rw-r--r-- 1 transfer transfer         48408 28. Nov 13:02 test_anonym_19-11-2023.log
-rw-r--r-- 1 transfer transfer    9329096219 28. Nov 13:03 test_anonym_21-11-2023.dmp.gz
-rw-r--r-- 1 transfer transfer         48407 28. Nov 13:03 test_anonym_21-11-2023.log

由于只想传输最新的模式,*.gz我可以执行以下操作来识别它们:*.log\.\/test_anonym_.*\.*

user@host:~/folder$ find . -type f -regex '\.\/test_anonym_.*\.*' | sort -r | head -n 2
./test_anonym_21-11-2023.log
./test_anonym_21-11-2023.dmp.gz

或者直接在遥控器上识别它们,ssh如下所示(效果很好):

user@host:~/folder$ ssh -qx user@host "ls -t /home/user/folder | sort -r | head -n 2"
test_anonym_21-11-2023.log
test_anonym_21-11-2023.dmp.gz

以下rsync命令传输太多,因为我只使用一种文件类型的模式,而没有识别两种类型的最新文件:

user@host:~/folder$ rsync -av --stats --include='test_anonym_*.gz' --exclude='test_*.*' user@host:/home/user/folder/ /home/user/folder/

test_anonym_19-11-2023.dmp.gz
test_anonym_21-11-2023.dmp.gz

在筛选了许多手册页和类似的帖子后,我尝试将ssh和一起使用,但它在从未完成的步骤中失败了:rsyncssh

ssh user@host "ls -t /home/user/folder/ | sort -r | head -n 2" | rsync -0 --stats --files-from=- -av user@host:/home/user/folder/ /home/user/folder/

我尝试使用rsyncwith--files-from=选项,但也失败了,因为我不确定两个示例中的语法:

rsync -a --stats --files-from=<(ssh user@host 'find . -type f -regex '\./test_anonym_.*\.*' | sort -r | head -n 2') --exclude='test_*.*' user@host:/home/user/folder/ /home/folder/folder/

rsync -a --stats --files-from=<(find . -type f -regex '\.\/test_anonym_.*\.*' | sort -r | head -n 2) --exclude='test_*.*' user@host:/home/user/folder/ /home/folder/folder/

我不确定如何将它们放在一起(或者是否可能)来查找和同步所需的文件;我现在真的被困住了。我怎样才能做到这一点?我的工作站使用zsh,我的遥控器都使用bash

在这里重申我的期望:我想rsync(有/没有ssh)来自远程的两个不同类型的文件,iEtest_anonym_21-11-2023.logtest_anonym_21-11-2023.dmp.gz女巫与我的模式匹配,并且是其类型的最新两个文件。

答案1

如果您有 GNU 工具,您可以使用它find来识别两个最近修改的文件并仅传输这些文件。由于需要从远程主机提取文件,该过程有点复杂,但这意味着ssh需要更多的参与。

如果我们可以假设最近修改的两个文件是一对要传输的文件,并且我们有带有 GNU 扩展名(或类似扩展名)的工具:

ssh -qn remoteHost "find folder -name 'test_anonym_*' -printf '%T@ %p\0'" |
    sort -z -k1,1rn |
    head -z -n2 |
    cut -z -d' ' -f2- |
    rsync --dry-run -av --files-from - --from0 remoteHost: "$HOME/folder"

如果您没有 GNU 工具,则必须小心意外的文件名,但只要您可以控制放置在以下位置的文件名,此管道就可以工作folder

ssh -qn remoteHost ls -t folder |
    head -n2 |
    rsync --dry-run -av --files-from - --from0 remoteHost:folder/ "$HOME/folder"

在这两种情况下,--dry-run当您对代码执行您期望的操作感到满意时,请将其删除。

如果您只能保证(比如说)文件dmp.gz并且您想要提取关联的log文件,那么情况会变得更加复杂。但你的问题似乎并不需要这样做。

答案2

如果目标用户的登录 shellremoteHost是 zsh,则只需执行以下操作:

rsync --old-args 'remoteHost:folder/test_anonym*.(log|gz)(.om[1,2])' ~/folder/

对于,在该行为不再是默认行为--old-args的较新版本中需要,会在调用 的远程 shell 命令行中按原样传递,并且 shell 将扩展该 glob,该 glob 与名称中的两个最新文件相匹配以 或 开头并以或结束。rsyncfolder/test_anonym*.(log|gz)(.om[1,2])rsync --serverfoldertest_anonym.gz.log

您可以通过运行以下命令来发现使用--old-args和不使用以及使用时行为的差异:--protect-argsrsyncstrace -e execve

$ strace -fe execve rsync --old-args 'remoteHost:folder/test_anonym*.(log|gz)(.om[1,2])' ~/folder/
[...]
[pid  8483] execve("/bin/ssh", ["ssh", "remoteHost", "rsync", "--server", "--sender", "-e.LsfxCIvu", ".", "folder/test_anonym*.(log|gz)(.om"...], 0x7ffceb4e2cf0 /* 52 vars */) = 0
[...]

Arg 未修改就通过了。

$ strace -fe execve rsync 'remoteHost:folder/test_anonym*.(log|gz)(.om[1,2])' ~/folder/
[...]
[pid  8489] execve("/bin/ssh", ["ssh", "remoteHost", "rsync", "--server", "--sender", "-e.LsfxCIvu", ".", "folder/test_anonym*.\\(log\\|gz\\)\\"...], 0x7ffc5bced518 /* 52 vars */) = 0
[...]

某些字符使用 转义\,无论这对远程 shell 是否有效。

$ strace -fe execve rsync --protect-args  'remoteHost:folder/test_anonym*.(log|gz)(.om[1,2])' ~/folder/
[...]
[pid  8507] execve("/bin/ssh", ["ssh", "remoteHost", "rsync", "--server", "--sender", "-se.LsfxCIvu"], 0x7ffc404a9900 /* 52 vars */) = 0
[...]

arg 不是在 shell 命令行中传递的,而是在较新的 rsync 协议中带内传递的。一般来说,这是最安全的,但这不允许我们使用 shell 的高级通配符。

如果 zsh 安装在远程主机上,但用户的登录 shell 是 bash,您可以使用如下技巧说服 bash 让 zsh 运行 rsync 服务器命令:

rsync --rsync-path='zsh -c "${BASH_EXECUTION_STRING#*\#\ }" # rsync' \
  --old-args 'remoteHost:folder/test_anonym*.(log|gz)(.om[1,2])' ~/folder/

远程主机上的 bash 将被要求评估:

zsh -c "${BASH_EXECUTION_STRING#*\#\ }" # rsync --server --sender -e.LsfxCIvu . folder/test_anonym*.(log|gz)(.om[1,2])

整个rsync --server...命令仅被视为注释。

$BASH_EXECUTION_STRINGbash 自动将 bash 设置为正在执行的内联脚本,并且我们从其中删除直到第一次出现 的所有内容#,因此zsh将进行解释:

rsync --server --sender -e.LsfxCIvu . folder/test_anonym*.(log|gz)(.om[1,2])

如果您不需要同步的能力,rsync但只需要传输这些文件,这样做可能更容易:

ssh remoteHost zsh << 'EOF' | (cd ~/folder && tar zxpvf -)
  cd folder &&
    tar zcf - test_anonym*.(log|gz)(.om[1,2])
EOF

答案3

我原来的问题:

“我想在不同环境中的两台服务器之间同步特定模式的最新两个文件。”

我的(传输)主机服务器包含最新文件:

drwxrwxr-x 2 transfer 4,0K 26. Mär 13:30 .
drwxr-xr-x 6 transfer 4,0K 20. Mär 11:01 ..
-rw-rw-r-- 1 transfer    0 26. Mär 13:30 test_26-03-2024.dmp.gz
-rw-rw-r-- 1 transfer    0 26. Mär 13:30 test_26-03-2024.log
-rw-rw-r-- 1 transfer    0 28. Nov 12:46 test_28-11-2023.dmp.gz
-rw-rw-r-- 1 transfer   21 28. Nov 13:04 test_28-11-2023.log
-rw-rw-r-- 1 transfer   0 26. Mär 13:30 test_anonym_17-03-2024.dmp.gz
-rw-rw-r-- 1 transfer    0 26. Mär 13:30 test_anonym_17-03-2024.log
-rw-r--r-- 1 transfer    0 28. Nov 13:00 test_anonym_19-11-2023.dmp.gz
-rw-r--r-- 1 transfer    5 29. Jan 13:35 test_anonym_19-11-2023.log
-rw-r--r-- 1 transfer    0 28. Nov 13:03 test_anonym_21-11-2023.dmp.gz
-rw-r--r-- 1 transfer  497 29. Jan 13:36 test_anonym_21-11-2023.log
-rw-rw-r-- 1 transfer    0 29. Jan 13:38 test_anonym_29-01-2024.dmp.gz
-rw-rw-r-- 1 transfer  201 29. Jan 13:37 test_anonym_29-01-2024.log
user@transfer:~/folder$ 

我的问题的解决方案:

我从我的(devops)其他服务器中识别了命名模式和文件类型的两个最新文件,test_anonym_*.*并将输出保存为文本文件:.log.dmp.gz

user@devops:~$ ssh -qx user@transfer 'ls -tr /home/user/folder | sort -k 8,8n -k 6,6M | grep test_anonym_* | head -n 2' > output.txt
...
user@devops:~$ nl output.txt 
     1  test_anonym_17-03-2024.dmp.gz
     2  test_anonym_17-03-2024.log

我现在可以将rsync文本文件中包含的文件发送到其他服务器:

user@devops:~$ rsync -arv --stats --include-from=output.txt --exclude=* user@transfer:folder/ ./folder/
user@transfer's password: 
receiving incremental file list
./
test_anonym_17-03-2024.dmp.gz
test_anonym_17-03-2024.log
...
sent 139 bytes  received 211 bytes  100,00 bytes/sec
total size is 0  speedup is 0,00

正确的文件已传输,我的主要问题已解决:

user@devops:~$ ls -la folder/
drwxrwxr-x 2 user user 4096 26. Mär 13:30 .
drwxr-xr-x 4 user user 4096 26. Mär 14:55 ..
-rw-rw-r-- 1 user user    0 26. Mär 13:30 test_anonym_17-03-2024.dmp.gz
-rw-rw-r-- 1 user user    0 26. Mär 13:30 test_anonym_17-03-2024.log

很高兴有: 现在的解决方案是通过管道将sshrsync命令合并为一个命令,或者将ls, sort,grep和保存headtmp--include-from=似乎没有人能够为此提供支持。

相关内容