ssh - executa comando remoto complexo

0

Eu quero executar o seguinte comando shell em uma máquina remota :

/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out

Este comando usa um binário chamado retail , que basicamente é um normal Linux tail com algum açúcar extra. Para obter mais informações, consulte o este repositório do github.

Quando eu insiro o comando acima dentro de um shell na máquina remota , ele faz o que eu quero, então o comando como está escrito está correto do ponto de vista funcional. Faz o que eu quero.

O problema é que eu quero executar esse comando dentro de um script no meu laptop e acionar a máquina remota.

Isso é o que tentei , mas todos os comandos não imprimem a saída desejada, em vez disso, eles imprimem nenhuma linha de log :

ssh [email protected] /bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out

Então tentei escapar [ e ] ou usar ' em vez de " e provavelmente todas as combinações, mas tudo não funcionou .

A saída desejada é: Comporte-se como um% normaltail e, em seguida, saia se a nova linha corresponder à especificada na cadeia. Novamente, quando eu o executo na máquina remota, ele funciona como descrito.

Eu estava me perguntando: Talvez retail não funcione no ssh? Eu tentei o Unix% normaltail e funciona em ssh. O Autor de retail diz que seu compatível com POSIX e um deles pode substituir seu sistema tail por ele. Então, eu acho que também é não é um problema do próprio binário.

Portanto, o problema realmente é: Como posso formatar o argumento do comando ssh , para que ele receba o comando corretamente?

Resposta ao comentário de Jaken551 :

Se você quer dizer:

ssh [email protected] '/bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out'

Então, sim, já tentei isso. Também imprime sem log line e não retorna ao prompt de entrada.

Resposta à resposta de Gerard H. Pille :

Infelizmente, o mesmo comportamento . Não imprime log e não retorna ao prompt de entrada. Para completar, eu tentei isso:

ssh [email protected] /bin/retail -f -u \'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\\"ajp-nio-8009\\"\]\' /opt/tomcat/logs/catalina.out

Resposta à resposta de Patrick :

Infelizmente, também é negativo. Para completar, tentei as duas soluções sugeridas. Aqui o primeiro :

CMD="$(printf "%q " /bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
ssh [email protected] "$CMD"

Resultado: Não imprime log e não retorna ao prompt de entrada.

E o segundo :

ssh -T [email protected] <<'EOF'
/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF

Resultado: Gera um pseudo-terminal, mas não o log e não retorna ao prompt de entrada :

 Pseudo-terminal will not be allocated because stdin is not a terminal.
Linux my-remote-server 4.1.15-1-lts #1 SMP Tue Dec 15 20:54:13 CET 2015 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

Como eu tentei algumas soluções agora, eu deveria tentar invocar um sh-script , que contém o comando retail como Gerard H Pille sugerido. Eu ainda gostaria de ter nice one-liner quando possível (sem escrever um script que contenha a linha).

Resposta à resposta Archemar :

Eu peguei o comando original, que eu especifiquei e adicionei um -t a ele, resultando no seguinte:

ssh -t [email protected] /bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out

e funcionou . Archemar você deve escrever seu comentário como uma resposta para que eu possa marcá-lo.

    
por kiltek 16.03.2018 / 09:40

3 respostas

3

em algum momento, os comandos lidam com terminais, pois esse não é um problema $PATH , você pode desejar que ssh aloque tty .

como por man ssh

-t Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very use‐ ful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

simplesmente use

ssh -t sshuser@host ...
    
por 16.03.2018 / 13:11
2

A recomendação de Jaken551 está próxima da solução atual, mas está um pouco fora devido ao nível extra de cotação aninhada. Vamos dar uma olhada no que está acontecendo com isso primeiro.

Minha técnica usual para isso é apenas lançar echo na frente do comando (não é perfeito, mas geralmente é bom o suficiente).

# Your original command which you say works locally
$ echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

# The command though ssh
$ ssh example.com echo "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out
INFORMATION [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler [ajp-nio-8009] /opt/tomcat/logs/catalina.out

# The command through ssh with the quotes
$ ssh example.com 'echo "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out'
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \["ajp-nio-8009"\] /opt/tomcat/logs/catalina.out

Portanto, observe a diferença nas saídas. Em ambas as versões ssh , o escape é diferente.

O que está acontecendo no primeiro exemplo ssh é que o primeiro nível de cotação está sendo removido pelo shell local, então ssh está recebendo vários argumentos ( echo , INFORMATION \[main\] ... ), que concatena juntos em um único argumento echo INFORMATION \[main\] ... , que então é avaliado através do shell no lado remoto como sh -c 'echo INFORMATION \[main\] ...' .

No segundo exemplo ssh , novamente o primeiro nível de cotação é eliminado pelo shell local, de modo que ssh recebe echo "INFORMATION \[main\] ..." , que então é avaliado no lado remoto como sh -c 'echo "INFORMATION \[main\] ..."' . Então, é um pouco melhor, mas você ainda está lidando com 2 níveis de conchas que retiram suas citações & escapa.

Existem duas maneiras de abordar isso. O primeiro é, em vez disso, passar o comando em STDIN, o que garantirá que seu comando só será processado por um shell uma vez, no tempo real de execução:

ssh -T example.com <<'EOF'
echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

No entanto, isso significa que o comando remoto não tem acesso ao seu TTY ou STDIN, portanto, se o comando precisar de STDIN, ele não funcionará.

A segunda abordagem é fazer com que o shell adicione um nível extra de cotação para você.

$ CMD="$(printf "%q " echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
$ ssh example.com "$CMD"
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

(você não precisa do intermediário $CMD , e você poderia fazer um inline ssh ... "$(printf "%q " ...)" , eu fiz isso separadamente para legibilidade)

TL; DR: qualquer um dos itens abaixo funcionará para você:

ssh -T [email protected] <<'EOF'
/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF

CMD="$(printf "%q " /bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
ssh [email protected] "$CMD"
    
por 16.03.2018 / 11:58
1

Seu trabalho teria sido muito mais fácil se você tivesse acabado de criar um script no outro sistema que fizesse o que queria, e então o chamasse sem nenhum parâmetro. Uma alternativa é criar um script no outro lado, que mostra quais parâmetros ele recebe, algo como echo_args.sh:

#!/bin/ksh

echo "$0 $@"
ARG=1
while [ $# -gt 0 ]
do
  echo "$ARG: $1"
  shift
  (( ARG++ ))
done

Então você pode ligar:

ssh [email protected] bin/echo_args.sh  -f -u \'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\\"ajp-nio-8009\\"\]\' /opt/tomcat/logs/catalina.out

e você recebe:

bin/echo_args.sh -f -u INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out
1: -f
2: -u
3: INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]
4: /opt/tomcat/logs/catalina.out

que mostra que os parâmetros chegam corretamente no outro lado. Agora você acabou de substituir o echo_args.sh pelo seu programa de varejo:

ssh [email protected] /bin/retail -f -u \'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\\"ajp-nio-8009\\"\]\' /opt/tomcat/logs/catalina.out
    
por 16.03.2018 / 11:52

Tags