Como substituir uma lista de espaços reservados em um arquivo de texto?

5

Eu tenho um arquivo de texto (configuração), mas o programa que lê o arquivo infelizmente não permite usar nenhum tipo de variável. Então, eu gostaria de usar um pré-processador que substitua um conjunto de espaços reservados no arquivo de configuração antes de passá-lo para o programa.

Eu posso definir o formato das variáveis da maneira que quiser (por exemplo, §SOME_DIR ). Se eu tivesse apenas algumas variáveis, provavelmente usaria sed :

sed  -e "s*§SOME_DIR*$SOME_DIR*g"  my.conf | target_prog

Mas a lista de variáveis é bastante longa e deve ser fácil de configurar - então prefiro colocar as variáveis em um arquivo de propriedades como

SOME_DIR=...
OTHER_DIR=...
...

e depois ligue

some_replace_tool  my.properties  my.conf  | target_prog

Estou procurando por "some_replace_tool". Alguma idéia?

    
por Chris Lercher 02.09.2011 / 12:51

5 respostas

3

Eu provavelmente escreveria algum script para expandir os shellibisells para gerar o arquivo de configuração de saída.

Aqui estão algumas dicas:

  1. aqui-strings (< < <) expande-se
  2. você pode carregar variáveis por ". varaibles.conf"
  3. env -i script.sh executará o script em ambiente limpo (sem variáveis extras)

Portanto, o script terá que construir um novo script temporário que irá fornecer as variáveis e cat here-string com vars expandidas. Então, para obter o resultado final, você terá que executar esse script gerado temporariamente por meio de env -i .

    
por 02.09.2011 / 21:56
2

@fred tem algo da ideia certa, mas um sistema muito mais simples pode ser:

sed -ne '/^#/d;s!^\([^=]*\)=\(.*\)$!s@@g!p' my.proprties > script.sed
sed -f script.sed my.conf | target_prog

Isso também gera apenas para linhas com "PROP = VALUE" e ignora as linhas de comentários.

Quebrando isso:

/^#/d                   - delete any comment lines (to ignore #PROP=VALUE)
s!^\([^=]*\)=\(.*\)$    - match any line with PROP=VALUE and place PROG into group 1 and VALUE into group 2
!s@@@g              - replace with s@GROUP1@GROUP2@g
!p                      - print the line, to override the -n

Você acaba com um script sed parecido com:

s@PROP1@VALUE1@g
s@PROP2@VALUE2@g
...
    
por 02.09.2011 / 23:13
0

Provavelmente, a maneira mais difundida e portátil de expansão simples de macros é o pré-processador C:

cat my.properties my.conf | cpp -P -DSOME_DIR=/a/b -DOTHER_DIR=/c | target_prog

Observe que você deve usar cat aqui, pois cpp aceita apenas um arquivo de entrada como parâmetro.

Mas, como você escreveu, você tem muitas variáveis, você pode preferir colocá-las em um arquivo:

#define SOME_DIR /a/b
#define OTHER_DIR /c

Em seguida, passe-o para cpp como:

cat my.properties my.conf | cpp -P -imacros definition.cpp | target_prog
    
por 02.09.2011 / 13:20
0

Existem dois pré-processadores que podem ser pré-processadores unix tradicionais: cpp (o pré-processador C) e m4 . Nenhum deles é adequado para o pré-processamento geral porque eles substituem as palavras em qualquer parte do texto e, no caso do cpp, impõe uma sintaxe de comentário. Um pré-processador geral razoável teria um indicador macro (ou seja, não expandisse todas as ocorrências de name , expanda apenas @name (por exemplo)).

Não existe nenhum pré-processador que eu considere um padrão de fato ou mesmo apenas comum. Um que é adaptado a uma variedade de formatos de entrada e disponível em muitas distribuições Linux é GPP .

Se você quiser se ater às ferramentas padrão, você pode usar o shell como um pré-processador em algumas circunstâncias. Construa uma string e depois execute

eval 'preprocessed=$(cat <<EOF)
$template
EOF'

Parâmetros e comandos do shell ( $var , $(command) , 'command' ) serão expandidos. Observe que você não pode impedir facilmente que o modelo chame comandos externos ou atribua a variáveis usadas pelo script, portanto, não use isso, a menos que você confie no local de origem do modelo.

    
por 03.09.2011 / 00:55
0

Atualização: Estendendo a idéia sed-to-sed de Arcege , você pode ter um layout mais gerenciável (tabular ou irregular) para seus modelos de localização / replicação, que podem ser inline ... e não há necessidade para um arquivo intermediário: (adicione um g antes do p'<<'EOF' para fazer várias alterações por linha ... Observe que foo , barbar , etc serão tratados por sed como expressões regulares.

I=$''; sed -nre "s/^([^ ]+) +/s$I$I/;s/$/$I/p"<<'EOF' |sed -f - file
foo           By the middle of June,
barbar        mosquitos were rampant,
foofoofoo     the grass was tawny, a brown dust
barbarbarbar  haze hung over the valley
EOF

(postagem original)
Você pode usar sed como um script executável, com um wrapper ...

Você pode definir sua localização e substituir o texto em um arquivo de texto separado,
mas para esta amostra é definida em linha ...

Este script converte seus pares de localização / replicação em expressões sed e cria dinamicamente o script executável

I=$''; set -f
printf "#!/bin/sed -f\n" > ~/bin/script.sed
while IFS= read -r line ;do
    ix=$(expr index "$line" " ")
    printf "s%s%s%s%s%s\n" $I ""${line:0:$((ix-1))}"" $I "${line:$ix}" $I 
done <<'EOF' >> ~/bin/script.sed
$text1 By the middle of June,
$text2 mosquitos were rampant,
$text3 the grass was tawny, a brown dust
$text4 haze hung over the valley
EOF
chmod +x ~/bin/script.sed

Este é o arquivo de teste a ser modificado.
'$' está bem, pois não está no final de uma linha (para sed), e não vai a qualquer momento ser exposto à casca mas qualquer token que não colidir com sed é bom. Você pode até usar #

echo '$text1 $text2 $text3 $text4' > file  

Supondo que ~/bin seja um diretório $ PATH, o comando a ser executado é:

script.sed  file   
    
por 02.09.2011 / 21:42