Passando cadeia de script para ssh de dentro de uma função de script bash - problema de avaliação de variáveis

3

Eu estou tentando escrever um script bash que executa um script remoto via ssh como abaixo:

#!/bin/bash
logfilepattern="*drupal*.gz php*.gz error*.gz"
function getlogcounts {
    echo "in getlogcounts"
    echo  $1
    echo  $2

    ssh $1 bash -c '  \  #script string starts here
    cd $2
    for file in 'ls $logfilepattern'
    do
     ls -l $file
    done
'
}

getlogcounts [email protected] "/var/log/mylogs"

$1 e $2 parecem encontrar ok na função, mas dentro da cadeia de script eles não parecem ter um valor ... portanto, cd $2 avalia para cd e ls $logfilepattern avalia para ls .

    
por user12514 04.10.2015 / 04:27

2 respostas

2

Aqui está uma versão que foi simplificada e, mais importante, a cotação foi corrigida (aspas duplas em torno de variáveis, aspas simples ao redor do texto não variável onde necessário)

#!/bin/bash
logfilepattern='*drupal*.gz php*.gz error*.gz'

function getlogcounts {
    echo in getlogcounts
    echo "$1"
    echo "$2"

    ssh "$1" "cd $2 ; ls -l $logfilepattern"
}

getlogcounts [email protected] /var/log/mylogs
    
por 04.10.2015 / 07:36
2

Você está executando um script na máquina remota. Esse script contém $2 e $logfilepattern (o texto entre aspas simples é passado literalmente como um argumento para o comando ssh , portanto, é um trecho de código para ser executado no outro lado). Estes referem-se a variáveis do shell em execução no lado da remoção.

Na verdade, você está executando dois shells no lado remoto, mas não é útil. O SSH sempre invoca um shell; você pode passar vários argumentos, mas eles estão apenas unidos aos espaços intermediários. O shell no lado remoto é executado

bash -c   \  #script string starts here
cd $2
…

A primeira linha invoca bash com dois argumentos: -c e um único espaço. Isso invoca um shell para não fazer nada. O resto do comando remoto é executado no shell invocado pelo SSH.

A maneira mais simples de fazer o que você está tentando fazer é

ssh "$1" "cd $2 && ls -l $logfilepattern"

Notas:

  • A análise da saída de ls é inútil : for file in 'ls *' é uma maneira complexa de escrever for file in * , exceto que a análise da saída % de ls será quebrado se os nomes dos arquivos contiverem caracteres especiais.
  • Os $2 e $logfilepattern são analisados como parte do script executado no lado remoto. Se eles contiverem algo como $(touch foo) , essa parte do código será executada. Neste caso de uso específico, não é necessariamente um problema, mas é algo que você precisa estar ciente.
  • Usar && após cd garante que o comando ssh retornará imediatamente com um status de falha se o comando cd falhar.

Se você quiser passar o conteúdo não modificado para um shell remoto por SSH, usar a linha de comando sozinha é problemático, porque o que quer que você passe é expandido no lado remoto. Um truque que geralmente funciona (mas nem sempre, depende da configuração do SSH no cliente e no servidor) é usar variáveis cujo nome começa com LC_ ; estas são consideradas informações sobre a localidade e geralmente transmitidas.

LC_DIRECTORY=$2 LC_LOGFILEPATTERN=$logfilepattern ssh "$1" 'cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN'

Observe a citação:

  • O comando para executar na máquina remota é cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN . Está entre aspas simples para passar esse texto literal como um argumento para o comando ssh .
  • $LC_DIRECTORY está entre aspas duplas no script executado no lado remoto para que o comando cd seja invocado no conteúdo da variável.
  • LC_LOGFILEPATTERN não tem aspas duplas porque é uma lista separada por espaço em branco de padrões de curingas, que é precisamente como uma expansão de variável sem aspas é tratada.

Se você não conseguir transmitir variáveis, será necessário adicionar uma camada de citações para proteger as variáveis cujo valor contenha caracteres especiais.

q_directory=$(printf %sa "$2" | sed s/\'/\'\\'\'/g)
q_directory="'${directory%a}'"
q_logfilepattern=$(printf %sa "$logfilepattern" | sed s/\'/\'\\'\'/g)
q_logfilepattern="'${q_logfilepattern%a}'"
ssh "$1" "logfilepattern=$q_logfilepattern; cd $q_logfilepattern && ls \$logfilepattern"
    
por 05.10.2015 / 02:05