Bash脚本从SSH远程主机复制倒数第二个文件至本地报错求助
问题原因
你遇到的scp: .: not a regular file错误,核心原因是本地脚本无法获取远程SSH会话里的变量值:
- 你的SSH heredoc用了
'ENDSSH',这段代码完全在远程主机B执行,pathFile和zipFile都是远程环境的变量,本地脚本根本拿不到它们的值。 - 执行scp时,
$pathFile和$zipFile是空的,导致scp的源路径变成$userName@machineB::,实际对应远程主机的当前目录。而scp默认不支持复制目录(需加-r参数),所以报错说.(当前目录)不是常规文件。
修复后的脚本
下面是修正后的脚本,核心思路是把远程获取的文件名传递回本地变量,再执行scp:
#!/bin/bash # 用$()替代反引号,更易读且支持嵌套 userName=$(whoami) myLocation=$(pwd) # 远程执行命令,获取倒数第二个文件的文件名,并传递回本地 remote_filename=$(ssh "$userName@machineB" ' remote_path="/somefolder/folder_1/businessfolder/" # 切换目录失败则直接退出,避免后续命令出错 cd "$remote_path" || exit 1 # 用ls -1tr确保每个文件名单独一行,按修改时间升序排列后取倒数第二个 ls -1tr | tail -n 2 | head -1 ') # 检查是否成功获取文件名 if [ -z "$remote_filename" ]; then echo "错误:未能获取到远程主机的目标文件" exit 1 fi # 执行scp,注意用双引号包裹变量,避免文件名含空格/特殊字符时出错 scp "$userName@machineB:/somefolder/folder_1/businessfolder/$remote_filename" "$myLocation"
更可靠的优化方案(避免ls解析文件名的坑)
用ls解析文件名存在隐患(比如文件名含空格、换行或特殊字符时会出错),推荐用find命令更稳定地获取目标文件:
#!/bin/bash userName=$(whoami) myLocation=$(pwd) remote_filename=$(ssh "$userName@machineB" ' remote_path="/somefolder/folder_1/businessfolder/" # 查找目录下的普通文件,输出修改时间戳+文件名,按时间戳排序后取倒数第二个 find "$remote_path" -maxdepth 1 -type f -printf "%T@ %f\n" | sort -n | tail -n 2 | head -1 | cut -d" " -f2- ') if [ -z "$remote_filename" ]; then echo "错误:未能获取到远程主机的目标文件" exit 1 fi scp "$userName@machineB:/somefolder/folder_1/businessfolder/$remote_filename" "$myLocation"
find的%T@输出文件的修改时间戳(精确到秒),结合sort -n按时间升序排列,确保排序逻辑准确。cut -d" " -f2-用来分离时间戳和文件名,即使文件名含空格也能正确提取。
内容的提问来源于stack exchange,提问作者CrazyCat
相关产品推荐
相关产品推荐

