Как мне вывести (огромный) вывод команды непосредственно на удаленный компьютер?

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

Чтобы сделать это более конкретным, вот как вы думаете, это может работать:

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

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

(Это использует соглашение - которое scp на самом деле не поддерживает - заменяет черту для исходного файла, чтобы сказать ему вместо этого получить его из stdin.)

dreeves
источник
Можете ли вы опубликовать URL вашего результата Google? Эксперты Exchange только показывают ответ внизу, если ваш реферал Google ...
Jon

Ответы:

76

Вы можете подключиться к ssh и запустить удаленную команду. В этом случае удаленная команда cat > big.txtбудет копировать стандартный 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 на приемнике и скопировать данные со стандартного ввода через сеть.

Однако у ncрешения есть несколько недостатков:

  • Там нет аутентификации; любой мог подключиться к порту 1234 и отправить данные в файл.
  • Данные не зашифрованы, как это было бы с ssh.
  • Если какая-либо машина находится за брандмауэром, выбранный порт должен быть открыт для правильного подключения и маршрутизации, особенно на принимающей стороне.
  • Оба конца должны быть установлены независимо и одновременно. С помощью этого sshрешения вы можете инициировать передачу только с одной из конечных точек.
Барри Браун
источник
Если это утешит вас, я склонен отметить, что вы приняты, так как это хорошо объясняет, что на самом деле происходит. (Если вы действительно хотите использовать его, вы можете включить решения FIFO pipe и netcat с некоторыми рекомендациями о том, почему вы можете предпочесть одно или другое! :)
dreeves
Готово. Netcat - удобная утилита. :)
Барри Браун
Как и в другом комментарии, если вы пропускаете через tar, вы можете использовать подстановку процесса: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'
BPF
источник
Ах, красавица, спасибо! Любая причина, чтобы предпочесть это или решение FIFO трубы?
dreeves
Я думаю, что подход mknod выполняет задачу точно так же, за исключением именованного канала.
BPF
4

Используйте nc (Net Cat), которому не нужно сохранять файл локально.

mcandre
источник
Ах, спасибо! Хотите включить эквивалент моего примера "echo .. | scp .."? И какие-либо причины, по которым вы знаете, предпочитают это другим ответам?
dreeves
2
Я настоятельно рекомендую не использовать ncдля этого. Однажды я выгружал необработанный образ диска с одной машины на другую, чтобы гораздо позже выяснить, что мой сетевой драйвер был неисправен и передал неисправные биты. Используйте scp, sshили что - нибудь еще , что скажет вам , когда есть ошибка передачи.
июля
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, предполагается, что "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, но не для суперпользователя, где большинство людей просто ищут способ передать ввод через scp.
allquixotic