Pode bash expandir uma variável de string entre aspas e / ou escape em palavras?

2

Eu tenho uma variável bash shell contendo uma string formada por várias palavras delimitadas por espaço em branco. A cadeia pode conter fugas, como espaço em branco em escape dentro de uma palavra. Palavras contendo espaço em branco podem ser citadas alternativamente.

Uma variável de shell usada sem aspas ( $FOO em vez de "$FOO" ) se torna várias palavras, mas aspas e escapes na string original não têm efeito.

Como uma string pode ser dividida em palavras, considerando caracteres citados e escapados?

Antecedentes

Um servidor oferece acesso restrito a ssh usando a opção ForceCommand no arquivo sshd_config para forçar a execução de um script, independentemente da linha de comando dada ao cliente ssh .

O script usa a variável SSH_ORIGINAL_COMMAND (que é uma sequência, definida por ssh , que contém a linha de comandos fornecida ao cliente ssh ) para definir sua lista de argumentos antes de continuar. Então, um usuário fazendo

$ ssh some_server foo 'bar car' baz

verá o script ser executado e terá SSH_ORIGINAL_COMMAND definido como foo bar car baz , o que se tornaria quatro argumentos quando o script for

set -- ${SSH_ORIGINAL_COMMAND}

Não é o resultado desejado. Então o usuário tenta novamente:

$ ssh some_server foo bar\ car baz

O mesmo resultado - a barra invertida no segundo argumento precisa ser escapada para o shell do cliente, então ssh o vê. E sobre estes:

$ ssh some_server foo 'bar\ car' baz
$ ssh some_server foo bar\ car baz

Ambos funcionam, assim como o printf "%q" quoting wrapper , que pode simplificar a citação do lado do cliente.

A cotação do lado do cliente permite que ssh envie a string corretamente citada para o servidor, de forma que ela receba SSH_ORIGINAL_COMMAND com a barra invertida intacta: foo bar\ car baz .

No entanto, ainda existe um problema porque set não considera a citação ou o escape. Existe uma solução:

eval set -- ${SSH_ORIGINAL_COMMAND}

mas é inaceitável. Considere

$ ssh some_server \; /bin/sh -i

Muito indesejável: eval não pode ser usado porque a entrada não pode ser controlada.

O que é necessário é o recurso de expansão de string de eval sem a parte de execução.

    
por starfry 21.11.2016 / 15:50

1 resposta

1

Use read :

read -a ssh_args <<< "${SSH_ORIGINAL_COMMAND}"
set -- "${ssh_args[@]}"

Isso analisará as palavras de SSH_ORIGINAL_COMMAND na matriz ssh_args , tratando a barra invertida ( \ ) como um caractere de escape. Os elementos da matriz são então dados como argumentos para set . Ele funciona com uma lista de argumentos passada por ssh da seguinte forma:

$ ssh some_server foo 'bar\ car' baz
$ ssh some_server foo bar\ car baz

Um printf "% q" citando o wrapper do ssh permite:

$ sshwrap some_server foo bar\ car baz
$ sshwrap some_server foo 'bar car' baz

Aqui está um exemplo de wrapper:

#!/bin/bash
h=$1; shift
QUOTE_ARGS=''
for ARG in "$@"
do
  ARG=$(printf "%q" "$ARG")
  QUOTE_ARGS="${QUOTE_ARGS} $ARG"
done
ssh "$h" "${QUOTE_ARGS}"
    
por 26.11.2016 / 16:37