Bash中能否通过管道将文件传入SSH的here-document并支持变量展开?
问题:用Here-Document实现SSH传输并解压文件
我原本用这条命令完成文件压缩、上传到服务器并解压到指定目录:
tar -pzcf - example.txt | ssh user@198.123.45.678 'cd /some-path/ && tar -zxf -'
但我想用here-document(heredoc)实现相同功能,尝试了下面的写法却无法正常工作:
tar -pzcf - example.txt | ssh user@198.123.45.678 /bin/bash <<EOF cd /some-path/ tar -zxf - EOF
需求背景
我有多段通过SSH在两台服务器上运行的本地脚本,这两台服务器对引号的处理方式不一致,heredoc能解决引号转义的问题。另外部分脚本需要用pipe viewer(pv)监控传输进度,但我还没找到把本地文件内容通过pv传入heredoc、让服务器处理的方法。
补充需求:支持变量展开
我需要从配置文件读取值,这也是引号问题的根源。比如下面的写法支持变量展开,但用heredoc时却无法正常接收管道内容:
先获取变量:
root_path=$(jq -r '.config.path.remote' config.json)
原来的变量展开写法:
tar -pzcf - example.txt | ssh user@198.123.45.678 "cd '$root_path' && tar -zxf -"
尝试的heredoc写法(无法接收管道内容):
root_path=$(jq -r '.config.path.remote' config.json) tar -pzcf - example.txt | ssh user@198.123.45.678 /bin/bash <<EOF cd "$root_path" tar -zxf - EOF
解决方案
问题核心是heredoc会占用远程bash的标准输入,导致本地tar输出的管道内容无法被远程的tar -zxf -读取。以下是两种可行的解决方法:
方法1:重定向管道到额外文件描述符
把本地管道的内容映射到远程bash的文件描述符3,让heredoc用标准输入,tar从fd3读取压缩包内容:
root_path=$(jq -r '.config.path.remote' config.json) tar -pzcf - example.txt | ssh user@198.123.45.678 /bin/bash 3<&0 <<EOF cd "$root_path" tar -zxf /dev/fd/3 EOF
方法2:用进程替换传递heredoc命令
通过进程替换将heredoc作为远程bash的命令源,保留标准输入给管道内容:
root_path=$(jq -r '.config.path.remote' config.json) tar -pzcf - example.txt | ssh user@198.123.45.678 bash <(cat <<EOF cd "$root_path" tar -zxf - EOF )
结合pv监控进度的写法
如果需要用pv显示传输进度,直接把它插入管道中间即可,两种方法都适用:
比如方法1结合pv:
root_path=$(jq -r '.config.path.remote' config.json) tar -pzcf - example.txt | pv | ssh user@198.123.45.678 /bin/bash 3<&0 <<EOF cd "$root_path" tar -zxf /dev/fd/3 EOF
内容的提问来源于stack exchange,提问作者Tomas Mulder
相关产品推荐
相关产品推荐

