如何将命令的(巨大)输出直接压缩到远程计算机?


50

请注意,我不能先将文件存储在本地-文件太大。

这个(令人讨厌的)页面(一直滚动到最底端)似乎给出了答案,但是我很难弄清特定于磁带驱动器的部分:

http://webcache.googleusercontent.com/search?q=cache:lhmh960w2KQJ:www.experts-exchange.com/OS/Unix/SCO_Unix/Q_24249634.html+scp+redirect&cd=3&hl=zh-CN&ct=clnk&gl=us

为了使它更具体,这是您认为它可能起作用的方式:

在本地计算机上:

% echo "pretend this string is a huge amt of data" | scp - remote.com:big.txt

(这使用的是惯例-scp实际上不支持-用破折号代替源文件,以告诉它从stdin获取它。)


您可以发布Google搜索结果的网址吗?专家交流只显示在底部的答案,如果你的推荐人是谷歌...
乔恩·

Answers:


76

您可以通过管道连接ssh并运行远程命令。在这种情况下,将使用远程命令cat > big.txt将stdin复制到big.txt文件中。

echo "Lots of data" | ssh user@example.com 'cat > big.txt'

只要您可以使用ssh连接到远程端,它就简单明了。

您也可以使用nc(NetCat)传输数据。在接收计算机上(例如host.example.com):

nc -l 1234 > big.txt

这将设置nc为侦听端口1234,并将发送到该端口的所有内容复制到该big.txt文件。然后,在发送机上:

echo "Lots of data" | nc host.example.com 1234

该命令将告诉nc发送方连接到接收器上的端口1234,并通过网络从stdin复制数据。

但是,该nc解决方案有一些缺点:

  • 没有身份验证;任何人都可以连接到端口1234并将数据发送到该文件。
  • 数据未加密(与加密一样)ssh
  • 如果任何一台计算机都位于防火墙后面,则必须打开所选端口以允许连接通过并正确路由,特别是在接收端。
  • 两端必须独立且同时设置。使用该ssh解决方案,您可以仅从端点之一启动传输。

如果有什么安慰的话,我倾向于标记您的接受,因为它很好地说明了实际情况。(如果您想真正解决问题,则可以包括FIFO管道和netcat解决方案,并提供一些指导说明为什么您可能更喜欢一个或另一个!:)
dreeves 2010年

做完了 Netcat是一个方便的实用程序。:)
巴里·布朗

与其他注释一样,如果要通过tar进行管道tar -cvzf >(ssh destination 'cat > file') huge_directory_tree
传输

1
SSH确实是必经之路。nc与之相比,它还默认提供对数据的加密和压缩,更重要的是:错误检测。我遇到的情况是我使用nc了故障的网络驱动程序,并且损坏的数据无法检测到。在这种情况下,SSH将失败,因为它无法解密/解压缩错误的数据。
jlh

15

使用ssh:

echo "pretend this is a huge amt of data" | ssh user@remote.com 'cat > big.txt'

啊,美丽,谢谢!有什么理由喜欢这种或FIFO管道解决方案?
dreeves,2010年

我认为mknod方法以完全相同的方式完成任务,除了命名管道。
bpf 2010年

4

使用nc(Net Cat),不需要在本地保存文件。


啊,谢谢!是否要包括我的“ echo .. | scp ..”示例的等效项?您知道有什么理由比其他答案更喜欢它吗?
dreeves 2010年

2
我强烈建议您不要使用nc它。我曾经将原始磁盘映像从一台计算机中转储到另一台计算机,但后来才发现我的网络驱动程序有故障并传输了错误的位。使用scpssh或其他任何会告诉你有一个传输错误。
jlh

2

使用FIFO管道:

mknod mypipe p
scp mypipe destination &
ls > mypipe

我无法在Linux系统上使用它。scp抱怨说mypipe不是常规文件。
巴里·布朗

1
出于同样的原因,也无法在Mac上运行。(不过,我不得不使用它mkfifo来创建管道。)
Barry Brown

1
也不在这里工作。但是,如果它确实对您scp <(ls) destination
有用

1

感谢丹尼斯·谢尔巴科夫!

当我在Hetzner云上尝试您的脚本时,

debug1: Sending command: scp -v -t backup-20180420120524.tar.xz.enc
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
Transferred: sent 4168, received 2968 bytes, in 0.0 seconds
Bytes per second: sent 346786.6, received 246944.0

但是只创建了一个没有内容的文件。由于实际内容已经使用openssl加密,因此我们实际上不需要scp。内置的linux ftp也具有强大的管道功能。所以这是我的(仍然很手动)解决方案:

#!/bin/bash

function join_e
{
  for word in $*; do
    echo -n "--exclude=$word "
  done
}


# Directory and file inclusion list
ILIST=(
  /home
)

# Directory and file exclusion list
ELIST=(
  var/lib/postgresql
)



export OPASS=fileencryptionpassword

nice -n 19 bash -c \
   "\
   tar $(join_e ${ELIST[@]}) -cpvf - -C / ${ILIST[*]} \
   | xz -c9e -T8 \
   | openssl enc -aes-256-cbc -pass env:OPASS \
   "

# decrypt with:
# cat backup.tar.xz.enc | openssl  aes-256-cbc -d  -pass env:OPASS | xz -dc | tar xv

# invocation procedure for ftp:
# $ ftp -np
# ftp> open storage.com
# ftp> user  storageuser storagepass
# ftp> put "| bash ~/backup.sh" backup.tar.xz.enc

1

这是一个替代解决方案:

上面所有建议ssh + cat的示例均假定“ cat”在目标系统上可用。

在我的情况下,系统(Hetzner备份)具有一组提供sftp的非常严格的工具,但没有完整的shell。因此,不可能使用ssh + cat。我想出了一个使用未记录的“ scp -t”标志的解决方案。完整的脚本可以在下面找到。

#!/bin/bash

function join_e
{
  for word in $*; do
    echo -n "--exclude=$word "
  done
}

CDATE=`date +%Y%m%d%H%M%S`

# Make password available to all programs that are started by this shell.
export OPASS=YourSecretPasswrodForOpenSslEncryption

#-----------------------------------------------

# Directory and file inclusion list
ILIST=(
  var/lib
)

# Directory and file exclusion list
ELIST=(
  var/lib/postgresql
)

# 1. tar: combine all files into a single tar archive
#      a. Store files and directories in ILIST only.
#      b. Exclude files and directories from ELIST.
# 2. xz: compress as much as you can utilizing 8 threads (-T8)
# 3. openssl: encrypt contents using a password stored in OPASS local environment variable
# 4. cat: concatenate stream with SCP control message, which has to be sent before data
#      a. C0600 - create a file with 600 permissions
#      b. 107374182400 - maximum file size
#         Must be higher or equal to the actual file size.
#         Since we are dealing with STDIN, we have to make an educated guess.
#         I've set this value to 100x times my backups are.
#      c. stdin - dummy filename (unused)
# 5. ssh: connect to the server
#      a. call SCP in stdin (-t) mode.
#      b. specify destination filename

nice -n 19 bash -c \
   "\
   tar $(join_e ${ELIST[@]}) -cpf - -C / ${ILIST[*]} \
   | xz -c9e -T8 \
   | openssl enc -aes-256-cbc -pass env:OPASS \
   | cat <(echo 'C0600 107374182400 stdin') - \
   | ssh username@server.your-backup.de "\'"scp -t backup-${CDATE}.tar.xz.enc"\'"\
   "

更新2019.05.08:

根据要求,下面是一个更简单,更短的版本。

#!/bin/sh

# WORKS ON LARGE FILES ONLY

cat filename.ext \
| cat <(echo 'C0600 107374182400 stdin') - \
| ssh user@host.dom 'scp -t filename.ext'

您是否可以通过删除所有不必要的东西并仅将其缩减为最少的使用示例来改善这一点scp -t?现在,您已经拥有一个高度定制/本地化的完整脚本。对于Hetzner Wiki来说是一件好事,但对于超级用户而言却不是,因为大多数人只是在寻找如何通过scp传递输入。
allquixotic
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.