Eu queria capturar alguns dados de vários servidores usando ssh e executar alguns comandos com algumas condições.
não quero fazer:
if ssh $host test -f /file; then
# If file exists
var=$(ssh $host long pipeline)
else
# if it doesn't
var=$(ssh $host another long pipeline)
fi
porque vai tornar o processo mais longo. Eu quero fazer o if else na máquina remota.
Eu tentei várias abordagens, mas não tive sorte.
var=$(ssh $host if [ -f /file ]\; then long pipeline1 \; else long pipeline2 \; fi)
Com base nesta resposta , funciona, mas o último comando do pipeline1 assume isso else
e o restante do pipeline2 como seus argumentos.
command: can't read else: No such file or directory
...
command: can't read fi: No such file or directory
Então eu tentei isso
var=$(ssh $host test -f /file \&\& pipeline1 \|\| pipeline2)
Novamente, o último comando de pipeline1 considerado ||
como seu argumento.
Eu também tentei abaixo (com base nisso ), que está funcionando:
do_this () {
if [ -f /file ]; then
pipeline1
else
pipeline2
fi
}
var=$(ssh $host "$(set); do_this")
No entanto, ele imprime mensagens de erro indesejadas que não afetam minha variável, mas é feio para o meu script.
bash: line 1: BASHOPTS: readonly variable
bash: line 8: BASH_VERSINFO: readonly variable
bash: line 24: EUID: readonly variable
bash: line 71: PPID: readonly variable
bash: line 82: SHELLOPTS: readonly variable
bash: line 92: UID: readonly variable
Alguma sugestão?
Atualizar
Acho que tenho que incluir o que é meu pipeline, basicamente é apenas um monte de processamento de texto:
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
De acordo com a resposta de Jetchisel , em resumo, tive que envolver meus comandos com aspas simples.
var=$(ssh $host 'if [ -f /file ]; then cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-' ; else cat otherfile | ... ; fi'
eu consegui tr: invalid option -- ';'
. tr
tratado ;
como seu argumento.
Funciona usando heredoc
:
var=$(ssh $host <<-EOF
if [ -f file ]; then
pipeline1
else
pipeline2
fi
EOF
)
No entanto, quebrou a coloração do vim por causa da regex que uso no sed. Vou aceitar heredoc
como resposta por enquanto.
Atualização 2 : acredito que minha pergunta não seja uma duplicata de Multiple command in sshpass , meu caso é mais específico, enquanto o outro thread pergunta em geral.
Dentro:
ssh
realmente executa um shell (o shell de login do usuário de destino) para interpretar o código que você passa como argumento. Se mais de um argumento for fornecido, o ssh os concatena com espaços e novamente o shell de login do usuário ohost
interpreta.Geralmente, você deseja passar um único argumento de código para
ssh
e certificar-se de que ele esteja entre aspas simples para garantir que nenhuma expansão seja feita pelo shell local.Se você sabe que o shell de login do usuário remoto é semelhante ao Bourne/POSIX, tudo o que você precisa fazer é:
Se o código a ser interpretado remotamente precisa ter aspas simples, você precisa inseri-los como
'\''
(deixe as aspas simples, insira aspas simples entre aspas (com barra invertida), insira novamente as aspas simples).Se você não puder garantir o shell do usuário remoto e não precisar passar dados para os comandos remotos sobre seu stdin (e nenhum dos comandos remotos lê de seu stdin, a menos que seja redirecionado para outro do que a conexão ssh), você pode fazer:
Ao citar o primeiro
EOF
, garantimos que nenhuma expansão seja feita no documento aqui pelo shell local. E invocamos explicitamentesh
para interpretar o código em seu stdin para que saibamos em qual sintaxe escrever o script.Essa abordagem também evita ter que escapar de aspas simples.
Sua
Pode ser escrito:
Então isso nos dá:
(que não funcionará se o shell de login do usuário remoto for, por exemplo, csh, tcsh, fish, rc, es, akanga cuja sintaxe é diferente daquela sintaxe semelhante a Bourne/POSIX)
Ou:
Eu fiz algo semelhante a este alguns anos atrás e aqui está como eu fiz isso.
Primeiro faça o teste do status de saída.
A verificação do status de saída.
A saída é
127
uma vez que não há/etc/fstabs
mas/etc/fstab
Agora mude
/etc/fstabs
para/etc/fstab
notar que não há nenhum à direitas
A verificação do status de saída novamente
A saída é
0
uma vez que existe/etc/fstab
na máquina remota.Em seguida, basta colocá-lo em uma variável e verificar o status de saída e executar seu script dependendo disso. Salve o status de saída em uma variável também.
Foi assim que sobrevivi a esse cenário, não estou dizendo que é uma solução perfeita, mas você pode conferir. A propósito, eu tenho a chave ssh encaminhada para o remotehost, então não há verificação de senha quando eu faço login via ssh. Também estou usando o bash como o shell de login em ambas as máquinas e é por isso que tenho o
exec bash -li
no final