Jak przesłać (ogromne) wyjście polecenia bezpośrednio do zdalnego komputera?

50

Pamiętaj, że nie mogę najpierw zapisać pliku lokalnie - jest za duży.

Ta (nieznośna) strona (przewiń do samego dołu) wydaje się dawać odpowiedź, ale mam problem z rozplątywaniem części specyficznej dla napędów taśmowych:

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

Aby to bardziej konkretne, oto jak można by pomyśleć, że może pracować:

Na komputerze lokalnym:

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

(Wykorzystuje to konwencję - której scp w rzeczywistości nie obsługuje - zastępując myślnik plikiem źródłowym, aby zamiast tego pobierał go ze standardowego wejścia).

dreeves
źródło
Czy możesz opublikować adres URL swojego wyniku Google? Wymiana ekspertów pokazuje odpowiedź tylko u dołu, jeśli Twój polecający to google ...
Jon

Odpowiedzi:

76

Możesz wykonać potok do ssh i uruchomić zdalne polecenie. W takim przypadku zdalne polecenie cat > big.txtkopiuje standardowe wejście do big.txtpliku.

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

Jest to łatwe i proste, o ile można użyć ssh do połączenia się ze zdalnym końcem.

Możesz także użyć nc(NetCat) do przesłania danych. Na komputerze odbierającym (np. Host.example.com):

nc -l 1234 > big.txt

Spowoduje to skonfigurowanie ncnasłuchiwania portu 1234 i skopiowanie wszystkiego, co zostanie wysłane do tego portu, do big.txtpliku. Następnie na urządzeniu wysyłającym:

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

To polecenie powie ncstronie wysyłającej, aby połączyć się z portem 1234 w odbiorniku i skopiować dane ze standardowego wejścia przez sieć.

Jednak ncrozwiązanie ma kilka wad:

  • Nie ma uwierzytelnienia; każdy może połączyć się z portem 1234 i wysłać dane do pliku.
  • Dane nie są szyfrowane, tak jak by to było ssh.
  • Jeśli którakolwiek maszyna znajduje się za zaporą ogniową, wybrany port musiałby być otwarty, aby umożliwić połączenie i poprawnie skierować, szczególnie po stronie odbierającej.
  • Oba końce muszą być ustawione niezależnie i jednocześnie. Dzięki temu sshrozwiązaniu możesz zainicjować transfer tylko z jednego z punktów końcowych.
Barry Brown
źródło
Jeśli to jakaś pociecha, jestem skłonny zaznaczyć, że twoje zostały zaakceptowane, ponieważ ładnie wyjaśnia, co się właściwie dzieje. (Jeśli naprawdę chcesz się z tym pogodzić, możesz dołączyć rozwiązania FIFO do rur i netcatów z pewnymi wskazówkami, dlaczego możesz wybrać jedno lub drugie! :)
dreeves
Gotowy. Netcat to przydatne narzędzie. :)
Barry Brown
Podobnie jak w innym komentarzu, jeśli przepływasz przez tar, możesz użyć substytucji procesu:tar -cvzf >(ssh destination 'cat > file') huge_directory_tree
Taywee
1
SSH jest rzeczywiście właściwą drogą. W porównaniu z nctym oferuje również domyślnie szyfrowanie i kompresję danych, a co ważniejsze: wykrywanie błędów. Miałem sytuacje, w których korzystałem ncz wadliwego sterownika sieciowego, a uszkodzone dane zostały przesłane niewykryte. SSH zawiedzie w takiej sytuacji, ponieważ nie może odszyfrować / zdekompresować wadliwych danych.
jlh
15

Za pomocą ssh:

echo "pretend this is a huge amt of data" | ssh [email protected] 'cat > big.txt'
bpf
źródło
Ach, piękna, dziękuję! Czy jest jakiś powód, aby preferować to rozwiązanie FIFO?
dreeves
Myślę, że podejście mknod wykonuje zadanie dokładnie w ten sam sposób, z wyjątkiem nazwanego potoku.
bpf
4

Użyj nc (Net Cat), który nie musi zapisywać pliku lokalnie.

Mcandre
źródło
Ach, dzięki! Chcesz dołączyć odpowiednik mojego przykładu „echo .. | scp ..”? Czy znasz jakieś powody, dla których wolisz to od innych odpowiedzi?
dreeves
2
Zdecydowanie odradzam używanie ncdo tego. Kiedyś zrzuciłem surowy obraz dysku z jednej maszyny na drugą, aby dowiedzieć się znacznie później, że mój sterownik sieciowy był wadliwy i przesłałem wadliwe bity. Stosowanie scp, sshlub cokolwiek innego, co powie, gdy pojawia się błąd transmisji.
jlh 10.10.16
2

Użyj rury FIFO:

mknod mypipe p
scp mypipe destination &
ls > mypipe
Sjoerd
źródło
Nie mogłem tego uruchomić w systemie Linux. scpnarzekał, że mypipe nie jest zwykłym plikiem.
Barry Brown
1
Z tego samego powodu nie działał też na komputerze Mac. (Musiałem jednak użyć mkfifofajki).
Barry Brown
1
Tu też nie działało. Ale jeśli to działa, a masz bash lub zsh, możesz to lepiej osiągnąć za pomocą zamiany procesu, jak w tym przykładzie:scp <(ls) destination
Taywee
1

Dzięki Denis Scherbakov!

Kiedy próbowałem twojego skryptu w chmurze Hetznera, dostałem

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

Ale utworzono tylko plik bez zawartości. Ponieważ rzeczywista treść jest już zaszyfrowana za pomocą openssl, tak naprawdę nie potrzebujemy scp. Wbudowany linux ftpma również świetne możliwości potokowania. Oto moje (wciąż dość ręczne) rozwiązanie:

#!/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
źródło
1

Oto alternatywne rozwiązanie:

Wszystkie powyższe przykłady sugerujące, że ssh + cat zakłada, że ​​„cat” jest dostępny w systemie docelowym.

W moim przypadku system (kopia zapasowa Hetznera) miał bardzo restrykcyjny zestaw narzędzi oferujących sftp, ale nie pełną powłokę. Dlatego użycie ssh + cat nie było możliwe. Wymyśliłem rozwiązanie, które wykorzystuje nieudokumentowaną flagę „scp -t”. Pełny skrypt można znaleźć poniżej.

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

Aktualizacja 2019.05.08:

Zgodnie z życzeniem poniżej jest o wiele prostsza i krótsza wersja.

#!/bin/sh

# WORKS ON LARGE FILES ONLY

cat filename.ext \
| cat <(echo 'C0600 107374182400 stdin') - \
| ssh [email protected] 'scp -t filename.ext'
Denis Scherbakov
źródło
Czy możesz to poprawić, usuwając wszystkie niepotrzebne rzeczy i po prostu sprowadzając to do absolutnego minimalnego przykładu użycia scp -t? W tej chwili masz kompletny skrypt, który jest wysoce niestandardowy / zlokalizowany w twoim środowisku. Dobra rzecz dla wiki Hetznera, ale nie dla superużytkownika, gdzie większość ludzi po prostu szuka sposobu przesyłania danych wejściowych przez scp.
allquixotic