Lê variáveis não-bash de um arquivo no script bash

4

Meu script bash precisa ler as variáveis de um arquivo de texto que contém centenas de variáveis, a maioria das quais está em conformidade com a sintaxe padrão da variável bash (por exemplo, VAR1=VALUE1 ). No entanto, algumas linhas neste arquivo podem ser problemáticas, e espero encontrar uma solução simples para lê-las no bash.

Veja como o arquivo se parece:

#comment
VAR1=VALUE1
VAR_2=VALUE_2
...
VAR5=VALUE 5 (ASDF)
VAR6=VALUE 6 #a comment
VAR7=/path/with/slashes/and,commas
VAR8=2.1
VAR9=a name with spaces
VAR_10=true
...
VAR_N=VALUE_N

As regras sobre a estrutura de arquivos incluem:

  • uma variável (com valor) por linha
  • a atribuição (=) não tem espaços ao redor
  • o nome da variável está na primeira coluna (a menos que seja uma linha de comentário)
  • comentários podem seguir o valor (após #)
  • os valores podem incluir espaços, parênteses, barras, vírgulas e outros caracteres
  • os valores podem ser números de ponto flutuante (2.1), inteiros, true / false ou strings.
  • Os valores de string
  • não são citados e podem ter mil caracteres de comprimento ou mais
  • o nome da variável contém apenas letras e sublinhados UPDATE: e números .

A maioria das variáveis é de um tipo que apenas me permitiria inserir o arquivo no meu script bash. Mas aqueles poucos problemáticos ditam uma solução diferente. Não tenho certeza de como lê-los.

    
por MountainX 22.02.2014 / 02:46

2 respostas

2

Embora seja possível transformar esse arquivo em um snippet de shell, é complicado. Você precisa ter certeza de que todos os caracteres especiais do shell estão corretamente citados.

A maneira mais fácil de fazer isso é coloque aspas simples ao redor do valor e substitua as aspas simples dentro do valor por '\'' . Você pode então colocar o resultado em um arquivo temporário e fornecer esse arquivo.

script=$(mktemp)
sed <"config-file" >"$script" \
  -e '/^[A-Z_a-z][A-Z_a-z]*=/ !d' \
  -e s/\'/\'\\\'\'/g \
  -e s/=/=\'/ -e s/\$/\'/

Eu recomendo fazer a análise diretamente no shell. A complexidade do código é quase a mesma, mas existem dois grandes benefícios: você evita a necessidade de um arquivo temporário e o risco de ter acidentalmente errado as citações e acaba executando uma parte de uma linha como um fragmento de shell ( algo como dangerous='$(run me)' ). Você também tem uma chance melhor de validar possíveis erros.

while IFS= read -r line; do
  line=${line%%#*}  # strip comment (if any)
  case $line in
    *=*)
      var=${line%%=*}
      case $var in
        *[!A-Z_a-z]*)
          echo "Warning: invalid variable name $var ignored" >&2
          continue;;
      esac
      if eval '[ -n "${'$var'+1}" ]'; then
        echo "Warning: variable $var already set, redefinition ignored" >&2
        continue
      fi
      line=${line#*=}
      eval $var='"$line"'
  esac
done <"config-file"
    
por 23.02.2014 / 01:09
1

Supondo que seu conteúdo esteja em um arquivo x.txt , você pode usar uma expressão sed :

sed -e 's/#.*//' -e 's/=.*$/="&"/g' -e 's/=//2' x.txt

A primeira expressão coloca tudo após o sinal = entre aspas. A segunda expressão remove o sinal extra = e a terceira expressão remove tudo entre # e " como eles são comentários.

A seguir, a cotação de RHS entre aspas simples:

sed -e "s/#.*//" -e "s/=.*$/='&'/g" -e "s/=//2" x.txt
    
por 22.02.2014 / 03:31