SSH管道传输tar包时如何在单会话发送带换行符的变量
最优实现方案
不需要做换行符替换、二次转义的冗余操作,全程仅建立1次SSH连接,仅需输入1次密码,无需远端安装任何软件、无需配置SSH免密登录,所有依赖均为类Unix系统默认自带的基础命令,可完整保留目录清单的换行、特殊字符格式。
直接在本地执行如下命令即可:
{ # 生成待备份目录的tar归档流 tar cvf - dirname/ # 写入自定义分隔符,拼接时间戳避免和传输内容撞串 echo "===TRANSFER_SPLIT_FLAG_$(date +%s)===" # 生成最大深度2级的目录结构流 tree -L 2 dirname } | ssh ${ARCHIVER} ' # 远端将接收的完整流写入临时文件 TMP_FILE="/tmp/archive_transfer_$$" cat > "${TMP_FILE}" # 拆分分隔符之前的内容写入tar归档文件 awk "/===TRANSFER_SPLIT_FLAG_[0-9]+===/{exit} {print}" "${TMP_FILE}" > '"${ARCHIVE}"'/dirname.tar # 拆分分隔符之后的内容写入目录清单,完整保留原有格式 awk "f; /===TRANSFER_SPLIT_FLAG_[0-9]+===/{f=1}" "${TMP_FILE}" | tail -n +2 > '"${ARCHIVE}"'/dirname_contents.log # 清理临时文件 rm -f "${TMP_FILE}" '
注意事项
- 之前遇到变量内换行被转成空格的核心原因是Shell的默认单词拆分(Word Splitting)机制:当你把
$contents变量直接拼接进SSH命令字符串时,本地Shell会将所有连续空白字符(换行、制表符、连续空格)解析为命令参数分隔符,替换为单个空格,和SSH传输本身无关。靠多层引号跨本地、远端两层Shell转义的写法容错率极低,一旦目录名或文件内容包含特殊字符很容易出故障,不建议使用。 - 上述方案通过单管道将两个待传输的数据流拼接后,通过同一个SSH会话传输到远端,再通过分隔符拆分写入对应文件,全程不会修改任何原始内容,不需要做特殊字符替换、转义操作。
- 命令用到的所有工具(
tar/tree/cat/awk/tail)都是系统默认预装的基础组件,不需要管理员权限安装额外软件包,普通用户对/tmp目录默认有读写权限,临时文件传输完成后会自动清理,不会残留垃圾。 - 如果传输的单文件大小超过
/tmp目录的可用空间,可以把临时文件路径改到你在远端有写入权限的其他目录即可。
内容的提问来源于stack exchange,提问作者Jo Shirley
相关产品推荐
相关产品推荐

