Bagaimana cara scp output (besar) dari sebuah perintah langsung ke mesin jarak jauh?

50

Perhatikan bahwa saya tidak dapat menyimpan file lebih dulu secara lokal - terlalu besar.

Halaman (menjengkelkan) ini (gulir semua jalan ke bawah) tampaknya memberikan jawaban tapi saya mengalami kesulitan menguraikan bagian yang khusus untuk tape drive:

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

Untuk membuat ini lebih konkret, inilah cara Anda berpikir itu mungkin berhasil:

Di mesin lokal:

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

(Itu menggunakan konvensi - yang scp sebenarnya tidak mendukung - mengganti tanda hubung untuk file sumber untuk mengatakannya untuk mendapatkannya dari stdin sebagai gantinya.)

Dreeves
sumber
Bisakah Anda memposting url hasil google Anda? Experts Exchange hanya menunjukkan jawaban di bagian bawah jika pengarah Anda adalah google ...
Jon

Jawaban:

76

Anda dapat melakukan pipe ke ssh dan menjalankan perintah jarak jauh. Dalam hal ini, perintah jarak jauh adalah cat > big.txtyang akan menyalin stdin ke dalam big.txtfile.

echo "Lots of data" | ssh [email protected] 'cat > big.txt'

Sangat mudah dan mudah, selama Anda dapat menggunakan ssh untuk menghubungkan ke ujung jarak jauh.

Anda juga dapat menggunakan nc(NetCat) untuk mentransfer data. Di mesin penerima (mis., Host.example.com):

nc -l 1234 > big.txt

Ini akan diatur ncuntuk mendengarkan port 1234 dan menyalin apa pun yang dikirim ke port tersebut ke big.txtfile. Kemudian, pada mesin pengirim:

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

Perintah ini akan memberi tahu ncdi sisi pengirim untuk terhubung ke port 1234 pada penerima dan menyalin data dari stdin di seluruh jaringan.

Namun, ncsolusinya memiliki beberapa kelemahan:

  • Tidak ada otentikasi; siapa pun dapat terhubung ke port 1234 dan mengirim data ke file.
  • Data tidak dienkripsi, karena dengan ssh.
  • Jika salah satu mesin berada di belakang firewall, port yang dipilih harus terbuka untuk memungkinkan koneksi melalui dan diarahkan dengan benar, terutama di sisi penerima.
  • Kedua ujung harus diatur secara independen dan simultan. Dengan sshsolusinya, Anda dapat memulai transfer hanya dari satu titik akhir.
Barry Brown
sumber
Jika itu adalah penghiburan, saya cenderung untuk menandai Anda diterima karena itu menjelaskan dengan baik apa yang sebenarnya terjadi. (Jika Anda ingin benar-benar meraihnya, Anda dapat menyertakan pipa FIFO dan solusi netcat dengan beberapa panduan tentang mengapa Anda lebih suka satu atau yang lain! :)
dreeves
Selesai. Netcat adalah utilitas praktis. :)
Barry Brown
Seperti dalam komentar lain, jika Anda melakukan pemipaan melalui tar, Anda dapat menggunakan subtitusi proses:tar -cvzf >(ssh destination 'cat > file') huge_directory_tree
Taywee
1
SSH memang jalan yang harus ditempuh. Dibandingkan dengan ncitu juga menawarkan enkripsi dan kompresi data Anda secara default dan yang lebih penting: deteksi kesalahan. Saya mengalami situasi di mana saya menggunakan ncdriver jaringan yang salah dan data yang rusak dapat dikirim tanpa terdeteksi. SSH akan gagal dalam situasi itu, karena tidak dapat mendekripsi / mendekompresi data yang salah.
jlh
15

Menggunakan ssh:

echo "pretend this is a huge amt of data" | ssh [email protected] 'cat > big.txt'
bpf
sumber
Ah, cantik, terima kasih! Ada alasan untuk memilih ini atau solusi pipa FIFO?
Dreeves
Saya pikir pendekatan mknod menyelesaikan tugas dengan cara yang persis sama kecuali untuk pipa bernama.
bpf
4

Gunakan nc (Net Cat), yang tidak perlu menyimpan file secara lokal.

mcandre
sumber
Ah terima kasih! Ingin memasukkan yang setara dengan contoh "echo .. | scp .." saya? Dan ada alasan Anda tahu lebih suka ini daripada jawaban lain?
Dreeves
2
Saya sangat merekomendasikan untuk tidak menggunakannya nc. Saya pernah membuang disk image mentah dari satu mesin ke komputer lain hanya untuk mengetahui kemudian bahwa driver jaringan saya salah dan mentransfer bit yang salah. Gunakan scp, sshatau apa pun yang akan memberi tahu Anda ketika ada kesalahan transmisi.
jlh
2

Gunakan pipa FIFO:

mknod mypipe p
scp mypipe destination &
ls > mypipe
Sjoerd
sumber
Saya tidak bisa menjalankan ini pada sistem Linux. scpmengeluh bahwa mypipe bukan file biasa.
Barry Brown
1
Juga tidak berfungsi pada Mac, karena alasan yang sama. (Namun, saya harus menggunakan mkfifountuk membuat pipa.)
Barry Brown
1
Juga tidak bekerja di sini. Tetapi jika itu berhasil untuk Anda, dan Anda memiliki bash atau zsh, Anda bisa lebih baik mencapainya dengan substitusi proses, seperti untuk contoh ini:scp <(ls) destination
Taywee
1

Thanx Denis Scherbakov!

Ketika saya mencoba skrip Anda di cloud Hetzner saya dapatkan

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

Tetapi hanya file tanpa konten yang dibuat. Karena konten aktual sudah dienkripsi dengan openssl, kita sebenarnya tidak perlu scp. Linux builtin ftpjuga memiliki kemampuan perpipaan yang bagus. Jadi, inilah solusi (masih sangat manual) saya:

#!/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
Johannes Winter
sumber
1

Inilah solusi alternatif:

Semua contoh di atas menyarankan ssh + cat menganggap bahwa "cat" tersedia di sistem tujuan.

Dalam kasus saya sistem (cadangan Hetzner) memiliki seperangkat alat yang sangat terbatas yang menawarkan sftp, tetapi tidak lengkap shell. Jadi tidak mungkin menggunakan ssh + cat. Saya datang dengan solusi yang menggunakan flag "scp -t" tidak berdokumen. Script lengkap dapat ditemukan di bawah.

#!/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 [email protected] "\'"scp -t backup-${CDATE}.tar.xz.enc"\'"\
   "

Pembaruan 2019.05.08:

Sesuai permintaan, di bawah ini adalah versi yang jauh lebih sederhana dan lebih pendek.

#!/bin/sh

# WORKS ON LARGE FILES ONLY

cat filename.ext \
| cat <(echo 'C0600 107374182400 stdin') - \
| ssh [email protected] 'scp -t filename.ext'
Denis Scherbakov
sumber
Bisakah Anda meningkatkan ini dengan menghapus semua hal yang tidak perlu dan hanya pare ini ke contoh minimum bagaimana menggunakannya scp -t? Saat ini Anda memiliki skrip lengkap yang sangat khusus / terlokalisasi untuk lingkungan Anda. Suatu hal yang baik untuk wiki Hetzner, tetapi tidak untuk Pengguna Super di mana kebanyakan orang hanya mencari cara menyalurkan input melalui scp.
allquixotic