1

Используя Linux, bash и OpenSSH, я могу выполнить сценарий оболочки на удаленном хосте по крайней мере тремя способами:

# Method 1: Script is never stored on the remote host
ssh <username>@<hostname> 'bash -s' < myShellScript

# Method 2: Script is permanently stored on the remote host
ssh <username>@<hostname> 'myShellScript'

# Method 3: Copy script to the remote host, execute it, and delete it
scp myShellScript <username>@<hostname>:~
ssh <username>@<hostname> 'myShellScript; rm -f myShellScript'

Я предпочитаю метод 1 методу 2, потому что он предотвращает размножение копий скрипта и связанные с ним головные боли при обслуживании.

Я предпочитаю метод 1 методу 3, потому что он быстрее и, как правило, "чище", чем копирование и удаление скрипта.

Но есть проблема, с которой мне нужно обойтись, если я хочу добиться своей цели придерживаться метода 1. myShellScript имеет следующую форму:

#!/bin/bash

# Do stuff...
myProgram input myProgramInputFile
# Do more stuff...

Здесь myProgram - это стандартная утилита, которая доступна на всех удаленных хостах, с которыми я мог бы захотеть взаимодействовать. Тем не менее, myProgramInputFile - это обычный файл, который существует только на моей локальной машине. Он не существует ни на одном из удаленных хостов.

Я хотел бы иметь возможность "связать" myShellScript и myProgramInputFile в один симпатичный "пакет", который выполняется на удаленном хосте через SSH без явного сохранения чего-либо в удаленной файловой системе, постоянно или временно. Это возможно?

1 ответ1

1

Я бы лучше скопировал хотя бы myProgramInputFile (как и метод 3 ); Я думаю, что это будет более надежным. Однако, есть способ заставить его работать с единственным методом 1.



Мой подход

Я советую вам сделать (локальный) скрипт, который копирует соответствующий файл на удаленную сторону, запускает выполнение и очищает впоследствии.

Нам понадобятся три локальных файла: myLocalScript (исполняемый файл), myRemoteScript и myProgramInputFile .

Содержание myLocalScript:

#!/bin/bash

# step 1: storing command line arguments to meaningful names
ssh_command="ssh $1"
script="$2"
input="$3"

# step 2: creating remote temporary file
remote_input=$($ssh_command 'mktemp')

# step 3: copying the content of local input file to the remote temporary file
cat "$input" | $ssh_command "cat > \"$remote_input\""

# step 4: sourcing the script to the remote side
$ssh_command "input=\"$remote_input\" bash -s" < "$script"

# step 5: removing the remote temporary file
$ssh_command "rm \"$remote_input\""

myRemoteScript будет выглядеть так:

# shebang is not needed, this script will effectively be sourced

# Do stuff…
myProgram input "$input"
# Do more stuff…

Файлы myProgramInputFile (локальный) и myProgram (удаленный) останутся такими же, как в текущих настройках.

Местное использование:

./myLocalScript <username>@<hostname> myRemoteScript myProgramInputFile

Технические примечания и объяснения:

  • На шаге 2 mktemp создает файл во временном каталоге на удаленном компьютере. Мы не хотим использовать mktemp -u чтобы избежать ситуации, когда кто-то еще создает файл с таким же именем между нашими шагами 2 и 3.
  • На шаге 3 мы могли бы использовать scp если бы использовали mktemp -u . Удаленный временный файл уже существует, поэтому мы используем cat для записи в него.
  • На шаге 4 myRemoteScript должен знать путь к временному файлу в контексте удаленного компьютера. Вот почему мы передаем наш локальный $remote_input качестве input переменной удаленному bash . Таким образом, когда myRemoteScript подается в упомянутый bash , $input в нем указывает путь к временному файлу.
  • Если мы сломаем удаленный bash (скажем, одним нажатием Ctrl + c), myLocalScript перейдет к шагу 5 и все равно выполнит очистку. Это причина, по которой очистка не заканчивается в myRemoteScript , хотя это может быть.


Единственный метод 1 подход

Благодаря Here Documents вы можете встроить myProgramInputFile в myShellScript .

Это будет легко, если myProgramInputFile представляет собой текстовый файл и myProgram может читать стандартный stdin (возможно, с myProgram input - синтаксис? или может быть, когда input опущен?)

myShellScript будет выглядеть так:

# shebang is not needed, this script will effectively be sourced

# Do stuff…

myProgram input - <<"EOF"
The content of myProgramInputFile is pasted here,
it continues here
and here,
and so on.
EOF

# Do more stuff…

Затем мы запустим его, как в методе 1:

ssh <username>@<hostname> 'bash -s' < myShellScript

Если myProgram не может прочитать стандартный stdin но удаленная система позволяет вам использовать /proc/self/ тогда мы должны написать ключевую строку в myShellScript следующим образом:

myProgram input /proc/self/fd/0 <<"EOF"

Если myProgramInputFile больше, чем текст, то мы должны кодировать его локально (см. uuencode , base64) и декодировать на удаленной стороне. Мы также должны проверить, нет ли строки EOF в закодированном тексте, измените разделитель документа здесь, если так. Обратите внимание, что base64 не использует _ поэтому E_O_F в этом случае совершенно безопасен (но, может быть, не с uuencode , я не знаю).


В качестве подтверждения концепции я распаковал значок Super User, закодировал его с помощью base64 и встроил в скрипт. Я решил продемонстрировать подход /proc/self/fd/0 с помощью cp но это также может быть cat > ~/SUfavicon.ico ; или лучше gzip -cd > ~/SUfavicon.ico ранее в трубе.

И, конечно, в вашем случае вместо myProgram будет cp .

Обратите внимание, что в этом случае {} важны, они делают документ здесь направленным на base64 -d .

# shebang is not needed, this script will effectively be sourced

{ base64 -d | gzip -cd | cp /proc/self/fd/0 ~/SUfavicon.ico ; } <<"E_O_F"
H4sICE3cXFkCA2Zhdmljb24uaWNvAO2XT2jTUBzHf2lnO1HXIAiKYHuSIYhzoCgIlV1EdtDDTmMg
CIKI7DQ9Taq71Il0VfBSmP9QmKziYRd3GCoqu40JIhtiB7sIOm1AcJ1r8/y+5bXEZ1KbtH07uMCH
3/pLvvm8lzYvC5FGAdJ1Qo3R+RaivUQUi1mfx9BPodeOns77ZPXXthZy25IgX2bbZkrz5uIjmvz+
lPKCBZAEmkOeH8/ABOjXt1AXb86NUg+Ov/AtSwOoy6gl1PYq+UtuA0RuHjCw32d+Dn6znrzwH/SZ
fy78w6gBr3lkOpH9DPg53nrNLzykVpzjDp8DatFLfrCXArkHlBLzfwcOgUANed4zE320/es4fRDz
7/Zw/XiP3TxHm5bGK9f/mJ/rv5StfP++8sjmxLU/7DWP7FHkiqhfUNuq5J+AM7h/jvDm/F06geOv
AJ5bBX0uwyvnTV5x/2bE/fsGmQK8U6hdTsGhsMXItI3XNq5hPQlbVPZjtRiKgKi1zvDV5bh9ndH/
9jDG/iCi6yuAVaOcXczuYy78ALPgOtjhND/Za/OzBvjtfARb19HP6a3Dr5GHDS4NvJL8g3795GOD
77bkv6rYn97w/9f+Ecl/Q7G/X/K/B0GF/t1gRRpDBoRU+MUYLjusgznR39lsvxjDAFh2GMdPFX4x
hrNOzwQF178NPHNwl8BEk39//Bk06eC9BfY06veH/Z1gFNwHKRAW/pMO8+5p9P2H/Wnp+A7hT0ru
qWasP1X88vqbbpL/FJgBs+AF0FX6PTx/Nvzr6x9W7B+T/BdV+fm7BshL/g6F/ozknq7z/Uur0bsL
PJbcv8ABRe9/Jekz///ntNt4m/z+N+M27xr8qz79n8A90M2fv//6vso+I0QJEF8jYcQNVnAjCiIG
KwYNZgIWtP4uhA2zNQriFRzz/NwwJF5yHzNCGgiy3wHSerE2FQAA
E_O_F

Запустите его как раньше:

ssh <username>@<hostname> 'bash -s' < myShellScript

Затем вы найдете ~/SUfavicon.ico на удаленной машине.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .