通过ssh将管道脚本和二进制数据传输到stdin

5

我希望远程执行一个bash脚本,该脚本需要消耗一个tar包并对其执行一些逻辑处理。但是有个技巧,我想只使用一个ssh命令来完成它(而不是先用scp命令传输tar包,然后再用ssh命令运行脚本)。

这个bash脚本的样子如下:

cd /tmp
tar -zx
./archive/some_script.sh
rm -r archive

我知道我可以将此脚本重新格式化为单行,并使用。
tar -cz ./archive | ssh $HOST bash -c '<commands>'

但是我的实际脚本非常复杂,所以我必须通过stdin将其管道传输到。这里的挑战是ssh只提供了一个输入管道(stdin),我想同时用于bash脚本和tarball。

1个回答

7
我提供了两种解决方案,都包括bash脚本和tarball在stdin中。

1. 在heredoc中嵌入base64编码的tarball

在此情况下,服务器接收到一个包含嵌入在heredoc中的tarball的bash脚本:
base64 -d <<'EOF_TAR' | tar -zx
<base64_tarball>
EOF_TAR

以下是完整的示例:
ssh $HOST bash -s < <(
# Feed script header
cat <<'EOF'
cd /tmp
base64 -d <<'EOF_TAR' | tar -zx
EOF

# Create local tarball, and pipe base64-encoded version
tar -cz ./archive | base64

# Feed rest of script
cat <<'EOF'
EOF_TAR
./archive/some_script.sh
rm -r archive
EOF
)

然而,在这种方法中,tar 不会在网络传输完整个 tar 包之前开始解压缩。

2. 在脚本后输入 tar 二进制数据

在这种情况下,bash 脚本作为 stdin 管道传入,其后是原始的 tar 文件数据。 bash 将控制权传递给 tar,它将处理 stdin 的 tar 部分:

ssh $HOST bash -s < <(
# Feed script.
cat <<'EOF'
function main() {
  cd /tmp
  tar -zx
  ./archive/some_script.sh
  rm -r archive
}
main
EOF
# Create local tarball and pipe it
tar -cz ./archive
)

与第一种方法不同的是,这种方法允许 tar 在网络传输 tarball 的同时开始提取。
顺便说一下,你问为什么我们需要 main 函数?为什么要先输入整个 bash 脚本,然后再输入二进制 tar 数据呢?好吧,如果二进制数据放在 bash 脚本的中间,会出现错误,因为 tar 会消耗 tarfile 结尾之后的内容,在这种情况下,它会吞掉一些 bash 脚本。所以,main 函数被用来强制整个 bash 脚本在 tar 数据之前出现。

1
相当聪明。我从未做过这种程度的双重嵌套。祝你好运并继续发布! - shellter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接