Яким чином я можу робити (величезний) вихід команди безпосередньо на віддалену машину?


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

Щоб зробити це більш конкретним, ось як ви думаєте, що це може працювати:

На локальній машині:

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

(Ось за допомогою конвенції - яка scp насправді не підтримує - про заміну тире на вихідний файл, щоб сказати йому, щоб отримати його з stdin.)


Чи можете ви опублікувати URL свого результату в Google? Експертна біржа показує відповідь лише внизу, якщо ваш референт є google ...
Jon

Відповіді:


76

Ви можете передавати в ssh та виконувати віддалену команду. У цьому випадку віддалена команда - cat > big.txtце скопіювати stdin у 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рішення ви можете ініціювати передачу лише з однієї з кінцевих точок.

Якщо це будь-яке втіху, я схильний відзначити ваше прийняте, оскільки це добре пояснює, що відбувається насправді. (Якщо ви хочете по-справжньому зафіксувати це, ви можете включити рішення FIFO pipe and netcat з деякими вказівками щодо того, чому ви можете віддати перевагу тому чи іншому! :)
dreeves

Зроблено. Netcat - це зручна утиліта. :)
Баррі Браун

Як і в іншому коментарі, якщо ви проходите через дьоготь, ви можете використовувати процедуру заміни: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 трубному рішенню?
дріве

Я думаю, що підхід mknod виконує завдання точно так само, за винятком названої труби.
bpf

4

Використовуйте nc (Net Cat), якому не потрібно зберігати файл локально.


Ах, дякую! Хочете включити еквівалент мого прикладу "ехо .. | scp .."? І з яких ви знаєте причин віддавати перевагу цьому іншим відповідям?
дріве

2
Настійно рекомендую не використовувати ncдля цього. Одного разу я перекидав неочищене зображення диска з однієї машини на іншу, лише щоб набагато пізніше з’ясувати, що мій драйвер мережі несправний і передав несправні біти. Використовуйте scp, sshабо що - небудь ще , що скаже вам , коли є помилка передачі.
jlh

2

Використовуйте трубу FIFO:

mknod mypipe p
scp mypipe destination &
ls > mypipe

Я не міг змусити це працювати в системі Linux. scpскаржився, що mypipe - це не звичайний файл.
Баррі Браун

1
Не працювали і на Mac, з тієї ж причини. (Мені довелося використати, mkfifoщоб створити трубу.)
Баррі Браун

1
Тут також не працювали. Але якщо це працює для вас, і у вас є bash або zsh, ви можете краще досягти цього за допомогою процесу заміни, як у цьому прикладі:scp <(ls) destination
Taywee

1

Дякуємо Денису Щербакову!

Коли я спробував твій сценарій на хмарі Гецнера, я потрапив

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 передбачає, що "кішка" доступна в системі призначення.

У моєму випадку система (резервна копія 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, але не для Super User, де більшість людей просто шукають, як передавати вхід через scp.
allquixotic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.