Come posso scp l'output (enorme) di un comando direttamente su una macchina remota?


50

Nota che non posso prima archiviare il file localmente - è troppo grande.

Questa (odiosa) pagina (scorrere fino in fondo) sembra dare una risposta, ma ho problemi a districare la parte specifica delle unità a nastro:

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

Per rendere questo più concreto, ecco come pensi che potrebbe funzionare:

Sulla macchina locale:

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

(Sta usando la convenzione - che scp in realtà non supporta - di sostituire un trattino con il file sorgente per dirgli di prenderlo invece da stdin.)


Puoi pubblicare l'URL del tuo risultato di Google? Scambio di esperti mostra la risposta in fondo solo se il tuo referente è google ...
Jon

Risposte:


76

È possibile reindirizzare in ssh ed eseguire un comando remoto. In questo caso, è il comando remoto cat > big.txtche copia lo stdin nel big.txtfile.

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

È semplice e intuitivo, purché sia ​​possibile utilizzare ssh per connettersi all'estremità remota.

È inoltre possibile utilizzare nc(NetCat) per trasferire i dati. Sulla macchina ricevente (ad es. Host.example.com):

nc -l 1234 > big.txt

Questo verrà impostato ncper ascoltare la porta 1234 e copiare tutto il big.txtfile inviato a quella porta nel file. Quindi, sul mittente:

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

Questo comando dirà ncsul lato di invio di connettersi alla porta 1234 sul ricevitore e copiare i dati dallo stdin attraverso la rete.

Tuttavia, la ncsoluzione presenta alcuni aspetti negativi:

  • Non c'è autenticazione; chiunque potrebbe connettersi alla porta 1234 e inviare dati al file.
  • I dati non sono crittografati, come sarebbero ssh.
  • Se una delle macchine si trova dietro un firewall, la porta scelta dovrebbe essere aperta per consentire la connessione e instradata correttamente, in particolare sul lato ricevente.
  • Entrambe le estremità devono essere impostate in modo indipendente e simultaneo. Con la sshsoluzione, è possibile avviare il trasferimento da uno solo degli endpoint.

Se è una consolazione, sono propenso a contrassegnare il tuo accettato poiché spiega bene cosa sta realmente succedendo. (Se volessi davvero conquistarlo, potresti includere la pipa FIFO e le soluzioni netcat con alcune indicazioni sul perché potresti preferire l'uno o l'altro! :)
Dreeves,

Fatto. Netcat è un'utilità utile. :)
Barry Brown,

Come nell'altro commento, se si tar -cvzf >(ssh destination 'cat > file') huge_directory_tree
esegue il

1
SSH è davvero la strada da percorrere. Rispetto ad ncesso offre anche la crittografia e la compressione dei dati per impostazione predefinita e, soprattutto, il rilevamento degli errori. Ho avuto situazioni in cui ho usato ncun driver di rete difettoso e i dati danneggiati sono stati trasmessi inosservati. SSH fallirà in quella situazione, perché non può decrittografare / decomprimere i dati difettosi.
jlh

15

Usando ssh:

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

Ah, bellissimo, grazie! Qual è il motivo per preferire questa o la soluzione di tubo FIFO?
Dreeves,

Penso che l'approccio mknod compia il compito esattamente allo stesso modo, tranne che per la named pipe.
bpf,

4

Utilizzare nc (Net Cat), che non deve salvare il file localmente.


Ah grazie! Vuoi includere l'equivalente del mio esempio "echo .. | scp .."? E quali motivi conosci per preferire questo alle altre risposte?
Dreeves,

2
Consiglio vivamente di non utilizzarlo ncper questo. Una volta ho scaricato un'immagine del disco non elaborato da una macchina all'altra solo per scoprire molto più tardi che il mio driver di rete era difettoso e trasferito bit difettosi. Usa scp, ssho qualsiasi altra cosa che vi dirà quando c'è un errore di trasmissione.
jlh

2

Utilizzare una pipa FIFO:

mknod mypipe p
scp mypipe destination &
ls > mypipe

Non riuscivo a farlo funzionare su un sistema Linux. scpsi è lamentato del fatto che mypipe non era un file normale.
Barry Brown,

1
Non ha funzionato nemmeno su un Mac, per lo stesso motivo. (Ho dovuto usare mkfifoper creare la pipa, però.)
Barry Brown,

1
Non ha funzionato neanche qui. Ma se funziona per te e hai bash o zsh, potresti farlo meglio con una sostituzione del processo, come per questo esempio:scp <(ls) destination
Taywee,

1

Grazie Denis Scherbakov!

Quando ho provato la tua sceneggiatura sul cloud di Hetzner ho capito

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

Ma è stato creato solo un file senza contenuto. Dato che il contenuto effettivo è già crittografato con openssl, in realtà non abbiamo bisogno di scp. Il built-in di Linux ftpha anche grandi capacità di piping. Quindi ecco la mia soluzione (ancora abbastanza manuale):

#!/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

Ecco una soluzione alternativa:

Tutti gli esempi precedenti che suggeriscono che ssh + cat presuppongono che "cat" sia disponibile sul sistema di destinazione.

Nel mio caso il sistema (backup di Hetzner) aveva un set di strumenti molto restrittivo che offre sftp, ma non una shell completa. Quindi usare ssh + cat non era possibile. Ho trovato una soluzione che utilizza flag "scp -t" non documentati. Lo script completo può essere trovato sotto.

#!/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"\'"\
   "

Aggiornamento 2019.05.08:

Come da richiesta, di seguito è una versione molto più semplice e più breve.

#!/bin/sh

# WORKS ON LARGE FILES ONLY

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

Puoi migliorarlo rimuovendo tutte le cose non necessarie e limitarlo al minimo esempio di come usare scp -t? In questo momento hai uno script completo altamente personalizzato / localizzato nel tuo ambiente. Una buona cosa per la wiki di Hetzner, ma non per il Super User in cui la maggior parte delle persone sta solo cercando come reindirizzare l'input tramite SCP.
allquixotic
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.