Wie kann ich die (große) Ausgabe eines Befehls direkt an einen Remote-Computer senden?

50

Beachten Sie, dass ich die Datei nicht zuerst lokal speichern kann - sie ist zu groß.

Diese (widerwärtige) Seite (ganz nach unten scrollen) scheint eine Antwort zu geben, aber ich habe Probleme, den Teil zu entwirren, der spezifisch für Bandlaufwerke ist:

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

Um dies konkreter zu machen, gehen Sie wie folgt vor:

Auf lokaler Maschine:

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

(Dabei wird die Konvention verwendet, die von scp nicht unterstützt wird: Ersetzen Sie die Quelldatei durch einen Bindestrich, um sie von stdin abzurufen.)

Dreeves
quelle
Können Sie die URL Ihres Google-Ergebnisses posten? Experts Exchange zeigt die Antwort am unteren Rand nur, wenn Ihr Referrer Google ist ...
Jon

Antworten:

76

Sie können eine Pipe in ssh ausführen und einen Remote-Befehl ausführen. In diesem Fall ist der Remote-Befehl, cat > big.txtder stdin in die big.txtDatei kopiert .

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

Es ist einfach und unkompliziert, solange Sie mit ssh eine Verbindung zum Remote-Ende herstellen können.

Sie können ncdie Daten auch mit (NetCat) übertragen. Auf dem empfangenden Computer (z. B. host.example.com):

nc -l 1234 > big.txt

Dies wird eingerichtet nc, um Port 1234 abzuhören und alles, was an diesen Port gesendet wird, in die big.txtDatei zu kopieren . Dann auf dem sendenden Rechner:

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

Dieser Befehl weist ncdie sendende Seite an, eine Verbindung zu Port 1234 des Empfängers herzustellen und die Daten von stdin über das Netzwerk zu kopieren.

Die ncLösung hat jedoch einige Nachteile:

  • Es gibt keine Authentifizierung. Jeder kann eine Verbindung zu Port 1234 herstellen und Daten an die Datei senden.
  • Die Daten werden nicht verschlüsselt, wie es bei wäre ssh.
  • Befindet sich einer der Computer hinter einer Firewall, muss der ausgewählte Port offen sein, damit die Verbindung ordnungsgemäß hergestellt und weitergeleitet werden kann, insbesondere auf der Empfängerseite.
  • Beide Enden müssen unabhängig und gleichzeitig eingerichtet werden. Mit der sshLösung können Sie die Übertragung von nur einem der Endpunkte aus starten.
Barry Brown
quelle
Wenn es ein Trost ist, neige ich dazu, Ihre Zustimmung zu kennzeichnen, da es gut erklärt, was tatsächlich vor sich geht. (Wenn Sie es wirklich schaffen wollen, können Sie die FIFO-Pipe- und Netcat-Lösungen mit einigen Hinweisen
einbeziehen,
Getan. Netcat ist ein praktisches Dienstprogramm. :)
Barry Brown
Wie im anderen Kommentar, wenn Sie durch Teer tar -cvzf >(ssh destination 'cat > file') huge_directory_tree
leiten
1
SSH ist in der Tat der richtige Weg. Im Vergleich dazu ncbietet auch die Verschlüsselung und Komprimierung Ihrer Daten standardmäßig und vor allem: Fehlererkennung. Ich hatte Situationen, in denen ich ncmit einem fehlerhaften Netzwerktreiber gearbeitet habe und beschädigte Daten unentdeckt übertragen wurden. SSH schlägt in dieser Situation fehl, da fehlerhafte Daten nicht entschlüsselt / dekomprimiert werden können.
18.
15

Ssh benutzen:

echo "pretend this is a huge amt of data" | ssh [email protected] 'cat > big.txt'
bpf
quelle
Ah, schön, danke! Gibt es einen Grund, diese oder eine FIFO-Rohrlösung zu bevorzugen?
Dreeves
Ich denke, dass der Ansatz von mknod die Aufgabe bis auf die Named Pipe genauso erfüllt.
bpf
4

Verwenden Sie nc (Net Cat), wodurch die Datei nicht lokal gespeichert werden muss.

mcandre
quelle
Ah danke! Möchten Sie das Äquivalent meines Beispiels "echo .. | scp .." einfügen? Und warum ziehen Sie dies den anderen Antworten vor?
Dreeves
2
Ich empfehle dringend davon abzuraten nc. Ich habe einmal ein Raw-Image von einem Computer auf einen anderen kopiert, um erst viel später festzustellen, dass mein Netzwerktreiber fehlerhaft war und fehlerhafte Bits übertragen hat. Verwendung scp, sshoder irgendetwas anderes , das Ihnen sagen , wenn ein Übertragungsfehler ist.
10.
2

Verwenden Sie eine FIFO-Pipe:

mknod mypipe p
scp mypipe destination &
ls > mypipe
Sjoerd
quelle
Ich konnte das auf einem Linux-System nicht zum Laufen bringen. scpbeschwerte sich, dass mypipe keine reguläre datei war.
Barry Brown
1
Funktionierte aus demselben Grund auch nicht auf einem Mac. (Ich musste jedoch verwenden mkfifo, um die Pipe zu erstellen.)
Barry Brown
1
Hat auch hier nicht funktioniert. Aber wenn es für Sie funktioniert und Sie bash oder zsh haben, können Sie dies besser mit einer Prozessersetzung erreichen, wie für dieses Beispiel:scp <(ls) destination
Taywee
1

Danke Denis Scherbakov!

Als ich dein Skript in der Hetzner Cloud ausprobiert habe, habe ich bekommen

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

Es wurde jedoch nur eine Datei ohne Inhalt erstellt. Da der eigentliche Inhalt bereits mit openssl verschlüsselt ist, brauchen wir scp eigentlich nicht. Das in Linux eingebaute Programm ftpverfügt auch über hervorragende Piping-Funktionen. Also hier ist meine (noch recht manuelle) Lösung:

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

Hier ist eine alternative Lösung:

In allen obigen Beispielen für ssh + cat wird davon ausgegangen, dass "cat" auf dem Zielsystem verfügbar ist.

In meinem Fall verfügte das System (Hetzner-Backup) über ein sehr restriktives Tool-Set, das SFTP anbot, jedoch keine vollständige Shell. Die Verwendung von ssh + cat war also nicht möglich. Ich habe eine Lösung gefunden, die das undokumentierte "scp -t" -Flag verwendet. Das vollständige Skript finden Sie weiter unten.

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

Update 2019.05.08:

Nachstehend finden Sie eine viel einfachere und kürzere Version.

#!/bin/sh

# WORKS ON LARGE FILES ONLY

cat filename.ext \
| cat <(echo 'C0600 107374182400 stdin') - \
| ssh [email protected] 'scp -t filename.ext'
Denis Scherbakov
quelle
Können Sie dies verbessern, indem Sie alle unnötigen Dinge entfernen und dies auf das Nötigste reduzieren scp -t? Im Moment haben Sie ein vollständiges Skript, das in hohem Maße an Ihre Umgebung angepasst / lokalisiert ist. Eine gute Sache für das Hetzner-Wiki, aber nicht für Superuser, bei denen die meisten Leute nur nach einer Möglichkeit suchen, Eingaben über scp weiterzuleiten.
allquixotic