bash - with - remover espaços arquivo txt




Como substituir espaços reservados ${} em um arquivo de texto? (10)

Eu quero canalizar a saída de um arquivo "template" para o MySQL, o arquivo com variáveis ​​como ${dbName} intercaladas. Qual é o utilitário de linha de comando para substituir essas instâncias e despejar a saída na saída padrão?


Atualizar

Aqui está uma solução do yottatsa sobre uma questão semelhante que apenas substitui variáveis ​​como $ VAR ou $ {VAR}, e é um breve one-liner

i=32 word=foo envsubst < template.txt

Claro que se eu e a palavra estão em seu ambiente, então é apenas

envsubst < template.txt

No meu Mac parece que foi instalado como parte do gettext e do MacGPG2

Resposta antiga

Aqui está uma melhoria para a solução de mogsie em uma questão semelhante, a minha solução não exige que você escale aspas duplas, mogsie faz, mas o seu é um forro!

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

O poder dessas duas soluções é que você só obtém alguns tipos de expansões de shell que não ocorrem normalmente $ ((...)), `...` e $ (...), embora a barra invertida seja uma escape de personagem aqui, mas você não precisa se preocupar que a análise tem um bug, e faz várias linhas muito bem.


Aqui está uma função Bash robusta que - apesar de usar o eval - deve ser segura de usar.

Todas as referências de variáveis ${varName} no texto de entrada são expandidas com base nas variáveis ​​do shell de chamada.

Nada mais é expandido: nem referências de variáveis ​​cujos nomes não estão entre {...} (como $varName ), nem substituições de comandos ( $(...) e sintaxe legada `...` ), nem substituições aritméticas ( $((...)) e sintaxe legada $[...] ).

Para tratar um $ como um literal, \ -escape-lo; por exemplo: \${HOME}

Note que a entrada só é aceita via stdin .

Exemplo:

$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)

Código fonte da função:

expandVarsStrict(){
  local line lineEscaped
  while IFS= read -r line || [[ -n $line ]]; do  # the `||` clause ensures that the last line is read even if it doesn't end with \n
    # Escape ALL chars. that could trigger an expansion..
    IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([$' '\1\2\3\4')
    # ... then selectively reenable ${ references
    lineEscaped=${lineEscaped//$'\4'{/\${}
    # Finally, escape embedded double quotes to preserve them.
    lineEscaped=${lineEscaped//\"/\\\"}
    eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
  done
}

A função pressupõe que nenhum caractere de controle 0x1 , 0x2 , 0x3 e 0x4 esteja presente na entrada, porque esses caracteres. são usados ​​internamente - já que a função processa o texto , que deve ser uma suposição segura.


Crie o rendertemplate.sh :

#!/usr/bin/env bash

eval "echo \"$(cat $1)\""

E template.tmpl :

Hello, ${WORLD}
Goodbye, ${CHEESE}

Renderize o modelo:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar

Eu encontrei este fio enquanto me perguntava a mesma coisa. Isso me inspirou nisso (cuidado com os backticks)

$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world

Eu sugiro usar algo como Sigil : https://github.com/gliderlabs/sigil

É compilado para um único binário, por isso é extremamente fácil de instalar em sistemas.

Então você pode fazer um simples one-liner como o seguinte:

cat my-file.conf.template | sigil -p $(env) > my-file.conf

Isso é muito mais seguro que o eval e mais fácil do que usar regex ou sed


Isso pode ser feito no próprio bash se você tiver controle do formato do arquivo de configuração. Você só precisa fonte (".") O arquivo de configuração em vez de subshell. Isso garante que as variáveis ​​sejam criadas no contexto do shell atual (e continuem a existir) em vez do subshell (onde a variável desaparece quando a sub-camada sai).

$ cat config.data
    export parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA
    export parm_user=pax
    export parm_pwd=never_you_mind

$ cat go.bash
    . config.data
    echo "JDBC string is " $parm_jdbc
    echo "Username is    " $parm_user
    echo "Password is    " $parm_pwd

$ bash go.bash
    JDBC string is  jdbc:db2://box7.co.uk:5000/INSTA
    Username is     pax
    Password is     never_you_mind

Se o seu arquivo de configuração não pode ser um shell script, você pode apenas 'compilá-lo' antes de executá-lo (a compilação depende do seu formato de entrada).

$ cat config.data
    parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA # JDBC URL
    parm_user=pax                              # user name
    parm_pwd=never_you_mind                    # password

$ cat go.bash
    cat config.data
        | sed 's/#.*$//'
        | sed 's/[ \t]*$//'
        | sed 's/^[ \t]*//'
        | grep -v '^$'
        | sed 's/^/export '
        >config.data-compiled
    . config.data-compiled
    echo "JDBC string is " $parm_jdbc
    echo "Username is    " $parm_user
    echo "Password is    " $parm_pwd

$ bash go.bash
    JDBC string is  jdbc:db2://box7.co.uk:5000/INSTA
    Username is     pax
    Password is     never_you_mind

No seu caso específico, você poderia usar algo como:

$ cat config.data
    export p_p1=val1
    export p_p2=val2
$ cat go.bash
    . ./config.data
    echo "select * from dbtable where p1 = '$p_p1' and p2 like '$p_p2%' order by p1"
$ bash go.bash
    select * from dbtable where p1 = 'val1' and p2 like 'val2%' order by p1

Em seguida, canalize a saída do go.bash no MySQL e voila, esperançosamente você não destruirá seu banco de dados :-).


Se você está aberto a usar o Perl , essa seria minha sugestão. Embora haja provavelmente alguns especialistas em sed e / ou AWK que provavelmente sabem como fazer isso muito mais facilmente. Se você tiver um mapeamento mais complexo com mais do que apenas dbName para suas substituições, poderá estendê-lo com bastante facilidade, mas também pode colocá-lo em um script Perl padrão nesse ponto.

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

Um script Perl curto para fazer algo um pouco mais complicado (lidar com várias chaves):

#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;

Se você nomear o script acima como replace-script, ele poderá ser usado da seguinte maneira:

replace-script < yourfile | mysql

Use /bin/sh . Crie um script de shell pequeno que defina as variáveis ​​e, em seguida, analise o modelo usando o próprio shell. Como assim (editar para lidar corretamente com novas linhas):

Arquivo template.txt:

the number is ${i}
the word is ${word}

Arquivo script.sh:

#!/bin/sh

#Set variables
i=1
word="dog"

#Read in template one line at the time, and replace variables (more
#natural (and efficient) way, thanks to Jonathan Leffler).
while read line
do
    eval echo "$line"
done < "./template.txt"

Saída:

#sh script.sh
the number is 1
the word is dog

file.tpl:

The following bash function should only replace ${var1} syntax and ignore 
other shell special chars such as `backticks` or $var2 or "double quotes". 
If I have missed anything - let me know.

script.sh:

template(){
    # usage: template file.tpl
    while read -r line ; do
            line=${line//\"/\\\"}
            line=${line//\`/\\\`}
            line=${line//\$/\\\$}
            line=${line//\\\${/\${}
            eval "echo \"$line\""; 
    done < ${1}
}

var1="*replaced*"
var2="*not replaced*"

template file.tpl > result.txt

template.txt

Variable 1 value: ${var1}
Variable 2 value: ${var2}

data.sh

#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"

parser.sh

#!/usr/bin/env bash

# args
declare file_data=$1
declare file_input=$2
declare file_output=$3

source $file_data
eval "echo \"$(< $file_input)\"" > $file_output

./parser.sh data.sh template.txt parsed_file.txt

parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2




templating