Как мне вывести (огромный) вывод команды непосредственно на удаленный компьютер?
Обратите внимание, что я не могу сначала сохранить файл локально - он слишком большой.
Эта (отвратительная) страница (прокручивается до конца), кажется, дает ответ, но у меня возникают проблемы при распутывании части, специфичной для ленточных накопителей:
Чтобы сделать это более конкретным, вот как вы думаете, это может работать:
На локальной машине:
% echo "pretend this string is a huge amt of data" | scp - remote.com:big.txt
(Это использует соглашение - которое scp на самом деле не поддерживает - заменяет черту для исходного файла, чтобы сказать ему вместо этого получить его из stdin.)
11 ответов
Вы можете подключиться к 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
Решение, вы можете начать передачу только с одной из конечных точек.
Используя ssh:
echo "pretend this is a huge amt of data" | ssh user@remote.com 'cat > big.txt'
Используйте nc (Net Cat), которому не нужно сохранять файл локально.
Вот альтернативное решение:
Во всех приведенных выше примерах, предлагающих 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:
As per request, below is a much simpler and shorter version.
#!/bin/sh
# WORKS ON LARGE FILES ONLY
cat filename.ext \
| cat <(echo 'C0600 107374182400 stdin') - \
| ssh user@host.dom 'scp -t filename.ext'
Используйте трубу FIFO:
mknod mypipe p
scp mypipe destination &
ls > mypipe
На этот вопрос слишком много сложных ответов, и они слишком специфичны для
scp
команда. Проблема того, как передать stdin в качестве аргумента командной строки, имеет гораздо более простое общее решение.
Предполагая оболочку bash, просто замените "-" на подстановку процесса:
$ echo "lots of data" | scp <(cat) host:path
В
<(…)
появится как
/dev/fd/#
к
scp
команда.
Спасибо Денису Щербакову!
Когда я попробовал твой скрипт на облаке Гетцнера, я получил
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
У меня была аналогичная проблема с MacOS/Zsh. Основываясь на ответе Рэя Баттерворта здесь и на этом от Adaephon в другом месте на SuperUser, это сработало для меня:
scp =(echo "Hi There!") remote_server:/Users/me/new_file.txt
Просто не забудьте указать имя файла во втором аргументе
scp
, иначе вы получите неожиданное имя на удаленном сервере.
1) Создайте FIFO pipe и cat на удаленной машине:
Remote# mknod /tmp/mypipe p # mkfifo /tmp/mypipe
Remote$ cat /tmp/mypipe > big.txt& exit
2) Отправьте данные на удаленный канал FIFO с локального компьютера с помощью scp:
Local$ echo "the huge amt of data string" | scp /dev/stdin user@Remote:/tmp/mypipe
echo "Lots of data" | ssh user@example.com 'tee big.txt'
С судо:
echo "Lots of data" | ssh user@example.com 'sudo -S tee big.txt'
Вы можете использовать для этого задания Curl, если, например, вы не можете использовать Cat на удаленном сервере. Используя протокол sftp, вы можете копировать все, что отправляете, на его стандартный ввод через ssh. Для аутентификации вы можете использовать ключ ssh вместо пароля. Я не пробовал ограничение размера, но оно должно работать, как и другие решения, проходить проверку подлинности и иметь чистый синтаксис.
Только не пытайтесь переключить Curl на протокол scp, потому что это не сработает. SCP-не работает
echo "pretend this string is a huge amt of data" | curl -k -T - -u user:password sftp://remote.host/big.txt