Jak zastąpić symbole zastępcze ${} w pliku tekstowym?

Chcę przekierować wyjście pliku "template" do MySQL, plik ma zmienne takie jak ${dbName} przeplatane. Co to jest narzędzie wiersza poleceń do zastąpienia tych wystąpień i zrzutu wyjścia do standardowego wyjścia?

Author: Yves M., 2009-01-06

14 answers

Sed !

Podany szablon.txt:

The number is ${i}
The word is ${word}

Musimy tylko powiedzieć:

sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt

Podziękowania dla Jonathana Lefflera za przekazanie wielu argumentów -e do tego samego wywołania sed.

 128
Author: user,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 13:49:01

Update

Oto rozwiązanie z yottatsa na podobne pytanie, które zastępuje tylko zmienne takie jak $VAR lub ${VAR} i jest krótkim jednoliniowym

i=32 word=foo envsubst < template.txt

Oczywiście jeśli i i word są w Twoim środowisku, to po prostu

envsubst < template.txt

Na moim Macu wygląda jakby był zainstalowany jako część gettext i z MacGPG2

Stara Odpowiedź

Oto ulepszenie rozwiązania z mogsie na podobne pytanie, moje rozwiązanie nie wymaga od Ciebie podwójnych cytatów, ale jego jest jednoliniowy!

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

Moc tych dwóch rozwiązań polega na tym, że dostajesz tylko kilka rodzajów rozszerzeń powłoki, które nie występują normalnie $((...)), `...', oraz $(...), choć odwrotny ukośnik jest znakiem ucieczki, ale nie musisz się martwić, że parsowanie ma błąd, i robi wiele linii dobrze.

 113
Author: plockc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Użyj /bin/sh. Utwórz mały skrypt powłoki, który ustawia zmienne, a następnie przeanalizuj szablon za pomocą samej powłoki. Podobnie jak tak (Edytuj, aby poprawnie obsługiwać nowe linie):

Szablon pliku.txt:

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

Plik 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"

Wyjście:

#sh script.sh
the number is 1
the word is dog
 40
Author: gnud,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-27 07:25:10

Myślałem o tym ponownie, biorąc pod uwagę ostatnie zainteresowanie, i myślę, że narzędzie, o którym pierwotnie myślałem, było m4, procesor makr dla autotools. Więc zamiast zmiennej, którą pierwotnie podałem, użyłbyś:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
 17
Author: Dana the Sane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 15:19:00

Szablon.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 szablon.txt parsed_file.txt

Parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2
 12
Author: ChaPuZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-20 21:31:19

Oto moje rozwiązanie z perlem oparte na poprzedniej odpowiedzi, zastępuje zmienne środowiskowe:

perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
 9
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 15:32:34

Oto solidna funkcja Bash , która-pomimo używania eval - powinna być bezpieczna w użyciu.

Wszystkie odwołania do zmiennych ${varName} w tekście wejściowym są rozwijane na podstawie zmiennych wywołujących powłokę.

nic innego nie jest rozszerzane: ani odwołania do zmiennych, których nazwy są Nie zamknięte w {...} (takie jak $varName), ani podstawienia poleceń ($(...) i składnia dziedziczona `...`), ani podstawienia arytmetyczne ($((...)) i składnia dziedziczona $[...]).

Traktować $ jako dosłowne, \ - uciec od niego; np.: \${HOME}

Zauważ, że wejście jest akceptowane tylko przez stdin .

Przykład:

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

Kod źródłowy funkcji:

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
}

funkcja zakłada, że nie 0x1, 0x2, 0x3, i 0x4 znaki sterujące są obecne na wejściu, ponieważ te znaki. są używane wewnętrznie - ponieważ funkcja przetwarza tekst , powinno to być bezpieczne założenie.

 7
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-21 03:43:14

Jeśli jesteś otwarty na używanie Perla , to moja sugestia. Chociaż są prawdopodobnie niektórzy sed i/lub AWK eksperci, którzy prawdopodobnie wiedzą, jak to zrobić znacznie łatwiej. Jeśli masz bardziej złożone mapowanie z więcej niż tylko dbName dla swoich zamienników, możesz to dość łatwo rozszerzyć, ale równie dobrze możesz umieścić to w standardowym skrypcie Perla w tym momencie.

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

Krótki skrypt Perla do zrobienia czegoś nieco bardziej skomplikowanego (obsługa wielu klucze):

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

Jeśli nadasz powyższy skrypt jako replace-script, można go użyć w następujący sposób:

replace-script < yourfile | mysql
 6
Author: Beau Simensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-27 07:21:24

Create rendertemplate.sh:

#!/usr/bin/env bash

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

I template.tmpl:

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

Renderuj szablon:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar
 5
Author: neu242,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 09:01:44

Plik.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
 4
Author: user976433,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-03 10:08:31

Sugerowałbym użycie czegoś w rodzaju Sigil : https://github.com/gliderlabs/sigil

Jest skompilowany do pojedynczego pliku binarnego, więc jest niezwykle łatwy w instalacji na systemach.

Wtedy możesz zrobić prostą jednowierszową, jak poniżej:

cat my-file.conf.template | sigil -p $(env) > my-file.conf
Jest to znacznie bezpieczniejsze niż eval i łatwiejsze niż użycie regex lub sed
 3
Author: spudfkc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-23 20:44:52

Znalazłem ten wątek zastanawiając się nad tym samym. To zainspirowało mnie do tego (ostrożnie z backtikami)

$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
 2
Author: GlueC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-16 12:58:01

Tu jest wiele opcji, ale pomyślałem, że rzucę swoje na kupę. Jest oparty na perlu, dotyczy tylko zmiennych w postaci ${...}, pobiera plik do przetworzenia jako argument i wypisuje przekonwertowany plik na standardowe wyjście:

use Env;
Env::import();

while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }

print "$text";

Oczywiście nie jestem osobą Perla, więc może być fatalna wada(chociaż działa dla mnie).

 2
Author: sfitts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-12 01:55:27

Można to zrobić w samym bash, jeśli masz kontrolę nad formatem pliku konfiguracyjnego. Wystarczy źródło (".") plik konfiguracyjny, a nie podskalowanie go. Zapewnia to, że zmienne są tworzone w kontekście bieżącej powłoki (i nadal istnieją), a nie subshell (gdzie zmienna zniknie, gdy subshell zakończy działanie).

$ 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

Jeśli Twój plik konfiguracyjny nie może być skryptem powłoki, możesz po prostu "skompilować" go przed wykonaniem (kompilacja zależy od Twojego format wejściowy).

$ 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

W twoim konkretnym przypadku przydałoby się coś w stylu:

$ 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

Następnie podłącz wyjście go.bash do MySQL i voila, mam nadzieję, że nie zniszczysz swojej bazy danych: -).

 1
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-06 12:15:06