我有这一行代码
scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5") logs/ios
运行时,只会 scp 五个文件中最新的一个,输出如下
iosTestOutput_20180831-175508-PDT.tgz 100% 199KB 21.7MB/s 00:00
cp: iosTestOutput_20180831-155546-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-142509-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-124259-PDT.tgz: No such file or directory
cp: iosTestOutput_20180831-115001-PDT.tgz: No such file or directory
然而,我实际上已经通过 ssh 进入目标目录并观察到这些文件存在,所以我不太确定我做错了什么。
答案1
只有第一个文件具有 scp 所需的绝对路径。
${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")
将评估为
${server}:${server_dir}/iosTestOutput_20180831-175508-PDT.tgz
iosTestOutput_20180831-155546-PDT.tgz
iosTestOutput_20180831-142509-PDT.tgz
...
为了清楚起见,我使用了换行符而不是空格。
本质上,您需要对使用输出五个文件中每个文件的完整路径的内容生成的列表进行循环。https://unix.stackexchange.com/a/240424/162359可能是一个好的开始。
(未经测试,只是一个粗略的草图)类似:
for bkp in $(ssh ${server} "find ${absolute_path_remote_dir} -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==5 {print $2}'")
do
scp -r ${bkp} logs/ios
done
rsync 中可能还有一些选项可以帮助您更优雅地完成您想要的任务。
答案2
当你跑的时候:
scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")
...发生的第一件事(重要的)是您的本地 shell 开始解释此处的命令替换:
$(ssh ${server} "ls -t ${server_dir} | head -5")
上面的命令替换大部分都按照您的想法执行,只是一旦文件名中存在空格或换行符(或制表符),它就会中断。例如,您可能有以下 5 个最新文件:
temp file
a
b
c
d
将为ssh ... ls -t | head -5
您提供:
a
b
c
d
temp file
...但是命令替换会从输出中删除换行符,从而返回以下字符串:
a b c d temp file
...现在与真实的原始文件名无法区分。
您可能永远不会遇到这样的文件名,但是保证安全并且永远不会被咬比相反更安全。
因此,我建议您安全地将文件名检索到本地系统,然后专门检索它们:
server=server-name-here ## replace with your values
server_dir=/tmp ## replace with your values
files=($(ssh "$server" "zsh -c 'print -N -- ${server_dir}/*(om.[1,5])'" 2>/dev/null ) )
for f in ${files[1,5]}
do
scp "${server}:${f}" logs/ios
done
最困难的部分是检索最近修改的五个文件的远程列表。在这里,我通过 ssh 连接到服务器并调用 zsh,以便使用其广泛的通配机制返回:
- ${server_dir} 中的文件
o
按m
氧化时间排序- 和 是常规文件 (
.
) - 以及前五个:
[1,5]
此处使用zsh 内置print
命令返回结果文件的以 null 分隔且以 null 结尾的列表。这个包含 null 的字符串通过 ssh 传回 zsh,zsh 将字符串拆分为 null 并将内容分配给数组files
。
然后,我们循环遍历该数组,小心地仅获取前五个元素(因为第六个是空值),然后scp
依次调用每个文件。
如果您愿意,您可以仔细构建一串远程文件名 ( ${server}:${file1} ${server}:${file2} ...
) 并scp
仅调用一次。一种可能性可能是:
scp ${server}:${(qq)^files[1,5]} logs/ios
...因为这指示 zsh 将字符串(${server},替换为您的真实服务器名称,后跟冒号)添加到数组的前五个元素。数组中的任何文件名都会被引用。
答案3
就像 hhoke1 所说,你缺少绝对路径。
ls -t | head -5 | xargs readlink -f
这应该为您提供 scp 的绝对路径,但似乎readlink
无法从管道读取输入,所以我使用了xargs
.