コマンドの(巨大な)出力をリモートマシンに直接scpするにはどうすればよいですか?


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=en&ct=clnk&gl=us

これをより具体化するために、ここにあなたがそれを思うだろうかだかもしれません動作します。

ローカルマシン上:

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

(これは、scpが実際にはサポートしていない)規則を使用しており、ソースファイルの代わりにダッシュを使用して、代わりにstdinから取得するよう指示します。)


Googleの結果のURLを投稿できますか?リファラーがグーグルの場合、Experts Exchangeの下部にのみ答えが表示されます...-
ジョン

回答:


76

sshにパイプして、リモートコマンドを実行できます。この場合、リモートコマンドはcat > big.txtstdinを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ソリューションを使用すると、1つのエンドポイントからのみ転送を開始できます。

それが慰めである場合、実際に何が起こっているかをうまく説明しているので、私はあなたのものを受け入れられるようにしたいと思います。あなたが本当にそれをクリンチしたい場合は(、あなたはどちらか一方を好むかもしれない理由についていくつかのガイダンスとFIFOパイプとnetcatをソリューションを含めることができます:)!
dreeves

できた Netcatは便利なユーティリティです。:)
バリーブラウン

他のコメントのように、tarをパイピングする場合は、プロセス置換を使用できますtar -cvzf >(ssh destination 'cat > file') huge_directory_tree
。– Taywee

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パイプソリューションを好む理由はありますか?
10

mknodアプローチは、名前付きパイプを除いてまったく同じ方法でタスクを達成すると思います。
bpf

4

ファイルをローカルに保存する必要のないnc(Net Cat)を使用します。


ああ、ありがとう!「echo .. | scp ..」の例に相当するものを含めたいですか?そして、あなたがこれを他の答えよりも好む理由は何ですか?
10

2
ncこれには使用しないことを強くお勧めします。一度、あるマシンから別のマシンに生のディスクイメージをダンプしたのは、ネットワークドライバーが故障していて、故障したビットを転送したことを後で知るためだけです。使用scpsshまたは伝送エラーがあるときを教えてくれる何か。
-jlh

2

FIFOパイプを使用します。

mknod mypipe p
scp mypipe destination &
ls > mypipe

これをLinuxシステムで動作させることができませんでした。scpmypipeは通常のファイルではないと不満を言いました。
バリーブラウン

1
同じ理由で、Macでも動作しませんでした。(mkfifoしかし、パイプを作成するために使用しなければなりませんでした。)
バリーブラウン

1
ここでも機能しませんでした。それはあなたのために仕事をし、そしてあなたはbashやzshのを持っている場合しかし、あなたはより良い、この例のように、プロセス置換でこれを実現することができます:scp <(ls) destination
Taywee

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を提供する非常に限定的なツールセットがありましたが、完全なシェルはありませんでした。そのため、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.