Execute o script local com arquivo de entrada local no host remoto

Execute o script local com arquivo de entrada local no host remoto

Tenho um script local que desejo executar em vários servidores remotos. A sintaxe de comando que estou usando é:

ssh <remote_server> "bash -s" < ./local_script.sh

Isso funciona bem e até me permite passar parâmetros paralocal_script.sh. No entanto, eu realmente gostaria de passar um arquivo de entrada para ele, como em:

local_script.sh < local_file.txt

Combinar essas duas afirmações dá:

ssh <remote_server> "bash -s" < ./local_script.sh < local_file.txt

Quando executo isso, recebo

bash: line 1: FOO: command not found
bash: line 2: BAR: command not found
bash: line 3: BAZ: command not found
...

onde FOO, BAR, BAZ, etc. são a primeira palavra em cada linha doarquivo_local.txt:

FOO     FOO_PARAM1
BAR     BAR_PARAM1
BAZ     BAZ_PARAM2
...

Então, parece que "bash -s"o servidor remoto está interpretandoarquivo_local.txtcomo um arquivo de script, em vez de um arquivo de entrada paralocal_script.sh. Existe alguma maneira de corrigir isso (além de criar um script wrapper)?

Responder1

Embora sshforneça dois fluxos de saída separados (para stdout e stderr), ele alimenta apenas um fluxo de entrada (stdin). Portanto, você precisaria passar o conteúdo do script e o arquivo de entrada por meio de mecanismos diferentes.

Por exemplo, um por meio de uma variável, um por meio de stdin:

LC_CODE=$(cat local_script.sh) ssh host 'eval "$LC_CODE"' < input

(assumindo que seu sshcliente passe a LC_*variável ( SendEnvin ssh_config) e o sshdservidor as aceite ( AcceptEnvin sshd_config))

Ou simplesmente passe o conteúdo do local_script.shcódigo do shell remoto, assumindo que o shell de login do usuário remoto é o correto para a sintaxe desse script:

ssh host "$(cat local_script.sh)" < input

Ou concatene o código e a entrada alimentada no sshstdin de como com:

{
  echo '{'; cat local_script.sh; echo '}; exit'
  cat input
} | ssh host 'bash -s some arguments'

Aqui, o uso bashporque bashcuidará da leitura da entrada, um byte por vez, para não ler além dessa }; exitlinha, enquanto nem todos os outros shells fazem isso.

Ou se sedno host remoto for GNU sed:

echo '#END-OF-SCRIPT' | cat local_script.sh - input |
  ssh host 'set some arguments; eval "$(sed -u "/^#END-OF-SCRIPT/q")"'

(aqui tendo o código avaliado pelo shell de login do usuário remoto e assumindo que seja do tipo Bourne)

Responder2

Aqui está uma solução mais elegante usando o operador BASH 'here-strings' ('<<<')

ssh -t host "/bin/bash <(base64 --decode <<<'$(base64 < script)' )"

A TI pega o script, converte-o em uma string base64, no comando SSH ele o converte de volta e o entrega ao bash como um nome de arquivo de pipe.

Para que um script crie um shell interativo, prefixe o 'nome do arquivo do pipe' com "--rcfile"

ssh -t host "/bin/bash --rcfile <(base64 --decode <<<'$(base64 < script)' )"

Mais sobre... https://antofthy.gitlab.io/info/apps/ssh_remote_commands.txt

Responder3

Isso funciona bem e ainda permite passar o conteúdo de vários arquivos para o script:

ssh host "bash -s -- '$(cat local_file_1.txt)'  '$(cat local_file_2.txt)'" < local_script.sh

A explicação é que sshserá executado bash -sno login com os argumentos do script sendo tudo o que vem depois --. Assim $1será o conteúdo de local_file_1.txte $2será o conteúdo de local_file_2.txt. bash -slê comandos de stdin que vem de < local_script.sh.

informação relacionada