Передача нескольких файлов через stdin (через ssh)

Передача нескольких файлов через stdin (через ssh)

У меня есть программа на удаленном хосте, выполнение которой мне нужно автоматизировать. Команда выполнения этой программы на той же машине выглядит примерно так:

/path/to/program -a file1.txt -b file2.txt

В этом случае file1.txtи file2.txtиспользуются для совершенно разных вещей в программе, поэтому я не могу просто catих вместе. Однако в моем случае file1.txtи file2.txt, которые я хочу передать в программу, существуют только на моем устройстве, а не на хосте, где мне нужно выполнить программу. Я знаю, что могу передать по крайней мере один файл через SSH, передав его через stdin:

cat file1.txt | ssh host.name /path/to/program -a /dev/stdin -b file2.txt

но, поскольку мне не разрешено хранить файлы на хосте, мне нужен способ получить file2.txtи там. Я думаю, это может быть возможно через злоупотребление переменными среды и творческое использование catи sedвместе, но я недостаточно хорошо знаю инструменты, чтобы понять, как я буду использовать их для достижения этого. Это выполнимо, и как?

решение1

Если файлы, указанные в качестве аргументов вашей программы, являются текстовыми файлами и вы можете контролировать их содержимое (знаете строки, которые не встречаются внутри них), вы можете использовать несколько here-документов:

{
    echo "cat /dev/fd/3 3<<'EOT' /dev/fd/4 4<<'EOT' /dev/fd/5 5<<'EOT'"
    cat file1
    echo EOT
    cat file2
    echo EOT
    cat file3
    echo EOT
} | ssh user@host sh

Вот catпример команды, которая принимает имена файлов в качестве аргументов. Вместо этого можно было бы:

echo "/path/to/prog -a /dev/fd/3 3<<'EOT' -b /dev/fd/4 4<<'EOT'

Замените каждый из EOTних на то, чего нет в каждом из файлов соответственно.

решение2

Возможно, это не совсем то, что вам нужно... Но, может быть, стоит рассмотреть возможность отправки tarball через канал, открытый с помощью ssh?

Вы сказали, что:

Мне не разрешено хранить файлы на хосте.

Возможно, у вас нет доступного для записи домашнего каталога или другого удобного места для долгосрочного хранения файлов, но я бы сказал, что маловероятно, что у вас нет доступного для записи места, даже если это временное место, tmpfsкоторое будет доступно только для вашего конкретного подключения.

Многим программам (и даже процедурам libc) требуется доступный для записи файл /tmp, поэтому весьма вероятно, что он вам будет доступен.

Затем вы можете использовать скрипт, который распакует tarball во временный каталог, запустит вашу программу и очистит ее через SSH-соединение.

Что-то вроде:

$ tar cf - file1.txt file2.txt |
  ssh host.name '
      set -e
      tmpdir=$(mktemp -d -t tmp.XXXXXXXXXX)
      cleanup () { rm -rf "$tmpdir"; }
      trap cleanup EXIT
      cd "$tmpdir"
      tar xf -
      /path/to/program -a file1.txt -b file2.txt
  '

Возможно, потребуется дополнительная осторожность с путями к файлам, и следует учитывать некоторые особые случаи (проверить их), но общий подход должен работать.

Если нет доступного для записи каталога, возможным подходом будет модификация, programчтобы взять tarball как единственный вход и распаковать его содержимое в память. Например, если programэто скрипт Python, то использование встроенного tarfileмодуля легко сделает что-то вроде этого.

решение3

Если вы можете установить прослушиватель TCP (может быть порт с более высоким номером), то вы можете использовать второй сеанс SSH для установки второго источника входных данных с помощью nc.

Пример:

На сервере есть такой скрипт ( ~/script.bash):

#!/usr/bin/env bash
cat "$1" | tr a 1
nc localhost "$2" | tr '[:lower:]' '[:upper:]'

А локально есть вот эти два файла:

$ cat a 
aaa
aaa
aaa
$ cat b
bbb
bbb
bbb

Теперь сначала запустите второй источник ( $servэто сервер):

ssh "$serv" nc -l -p 2222 -q1 <b &

И выполните команду правильно:

$ ssh "$serv" ./script.bash - 2222 <a
111
111
111
BBB
BBB
BBB
[1]+  Done                    ssh "$serv" nc -l -p 2222 -q1 < b

решение4

Если вам разрешено перенаправлять порты через sshи у вас есть доступ к wgetна удаленной машине и к busyboxна локальной машине, вы можете сделать что-то вроде:

mkdir /tmp/test; cd /tmp/test
echo 1st_file > 1st_file
echo 2nd_file > 2nd_file

busybox httpd -f -p 127.0.0.1:11080 &
ssh USER@HOST -R 10080:127.0.0.1:11080 '
        cat <(wget -q -O- http://localhost:10080/1st_file) \
            <(wget -q -O- http://localhost:10080/2nd_file)
'
kill $!

( catв качестве примера используется программа, которая принимает два файловых аргумента).

Важна только возможность переадресации портов через -R-- вместо http можно использовать другие методы, например, если ваш netcatподдерживает параметры -dи -N:

nc -Nl localhost 11001 < 1st_file &
nc -Nl localhost 11002 < 2nd_file &
ssh USER@HOST -R 10001:localhost:11001 -R 10002:localhost:11002 '
        cat <(nc -d localhost 10001) <(nc -d localhost 10002)

Могут существовать способы замены <(...)подстановок процессов, если оболочка входа на удаленной машине не похожа на ksh или bash.

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

Связанный контент