it-swarm.com.de

Wie ersetze ich $ {} Platzhalter in einer Textdatei?

Ich möchte die Ausgabe einer "Template" -Datei nach MySQL leiten, wobei die Datei Variablen wie ${dbName} Enthält. Was ist das Befehlszeilenprogramm, um diese Instanzen zu ersetzen und die Ausgabe auf die Standardausgabe zu sichern?

129
Dana the Sane

Sed !

Gegeben template.txt:

 Die Zahl ist $ {i} 
 Das Wort ist $ {Word} 

wir müssen nur sagen:

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

Vielen Dank an Jonathan Leffler für den Tipp, mehrere -e Argumente für denselben sed Aufruf.

154
user

Aktualisieren

Hier ist eine Lösung von yottatsa zu einer ähnlichen Frage, die nur Variablen wie $ VAR oder $ {VAR} ersetzt und nur einzeilig ist

i=32 Word=foo envsubst < template.txt

Natürlich, wenn i und Word in Ihrer Umgebung sind, dann ist es gerecht

envsubst < template.txt

Auf meinem Mac sieht es so aus, als wäre es als Teil von gettext und von MacGPG2 installiert worden

Alte Antwort

Hier ist eine Verbesserung der Lösung von mogsie zu einer ähnlichen Frage, meine Lösung erfordert nicht, dass Sie doppelte Anführungszeichen setzen, mogsie's tut es, aber sein ist ein Einzeiler!

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

Die Stärke dieser beiden Lösungen besteht darin, dass Sie nur wenige Arten von Shell-Erweiterungen erhalten, die normalerweise nicht auftreten: $ ((...)), `...` und $ (...), obwohl Backslash ist hier ein Escape-Zeichen, aber Sie müssen sich keine Sorgen machen, dass das Parsen einen Fehler aufweist, und es macht mehrere Zeilen in Ordnung.

145
plockc

Verwenden /bin/sh. Erstellen Sie ein kleines Shell-Skript, mit dem die Variablen festgelegt werden, und analysieren Sie die Vorlage mithilfe der Shell. Gefällt mir (bearbeiten, um Zeilenumbrüche korrekt zu behandeln):

Datei template.txt:

the number is ${i}
the Word is ${Word}

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

Ausgabe:

#sh script.sh
the number is 1
the Word is dog
42
gnud

Angesichts des jüngsten Interesses habe ich erneut darüber nachgedacht, und ich glaube, das Werkzeug, an das ich ursprünglich gedacht habe, war m4 , der Makroprozessor für Autotools. Anstelle der ursprünglich angegebenen Variablen würden Sie also Folgendes verwenden:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
20
Dana the Sane

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
12
ChaPuZ

hier ist meine Lösung mit Perl, die auf früheren Antworten basiert und Umgebungsvariablen ersetzt:

Perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
9
Thomas

Hier ist eine robuste Bash-Funktion, die - trotz der Verwendung von eval - sicher sein sollte.

Alle ${varName} - Variablenverweise im Eingabetext werden basierend auf den Variablen der aufrufenden Shell erweitert.

Nichts anderes wird erweitert: Weder Variablenverweise, deren Namen nicht eingeschlossen sind {...} (Wie $varName), Noch Befehlsersetzungen ($(...) und Legacy-Syntax `...`), Noch arithmetische Ersetzungen ($((...)) und Legacy-Syntax $[...]).

Um einen $ Als Literal zu behandeln, \ - entkommen Sie ihm; z.B.:\${HOME}

Beachten Sie, dass Eingaben nur über stdin akzeptiert werden.

Beispiel:

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

Funktionsquellcode:

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
}

Die Funktion geht davon aus, dass keine Steuerzeichen 0x1, 0x2, 0x3 Und 0x4 In der Eingabe vorhanden sind, da diese Zeichen. werden intern verwendet - da die Funktion Text verarbeitet , sollte dies eine sichere Annahme sein.

9
mklement0

Erstellen rendertemplate.sh:

#!/usr/bin/env bash

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

Und template.tmpl:

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

Rendern Sie die Vorlage:

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

Wenn Sie bereit sind, Perl zu verwenden, wäre das mein Vorschlag. Obwohl es wahrscheinlich einige sed und/oder AWK Experten gibt, die wahrscheinlich wissen, wie man das viel einfacher macht. Wenn Sie eine komplexere Zuordnung mit mehr als nur dbName für Ihre Ersetzungen haben, können Sie diese ziemlich einfach erweitern, aber Sie können sie an dieser Stelle genauso gut in ein Standard-Perl-Skript einfügen.

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

Ein kurzes Perl-Skript, um etwas etwas komplizierteres zu machen (mit mehreren Schlüsseln umgehen):

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

Wenn Sie das obige Skript als Ersatzskript bezeichnen, kann es folgendermaßen verwendet werden:

replace-script < yourfile | mysql
5
Beau Simensen

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
4
user976433

Ich würde vorschlagen, etwas wie Sigil zu verwenden: https://github.com/gliderlabs/sigil

Es ist zu einer einzigen Binärdatei kompiliert, sodass die Installation auf Systemen extrem einfach ist.

Dann können Sie einen einfachen Einzeiler wie den folgenden erstellen:

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

Dies ist viel sicherer als eval und einfacher als die Verwendung von Regex oder sed

3
spudfkc

Viele Möglichkeiten hier, aber ich dachte, ich würde meine auf den Haufen werfen. Es basiert auf Perl, zielt nur auf Variablen der Form $ {...} ab, verwendet die zu verarbeitende Datei als Argument und gibt die konvertierte Datei auf stdout aus:

use Env;
Env::import();

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

print "$text";

Natürlich bin ich nicht wirklich eine Perl-Person, daher kann es leicht zu einem schwerwiegenden Fehler kommen (funktioniert jedoch bei mir).

2
sfitts

Ich habe diesen Thread gefunden, als ich mich das Gleiche gefragt habe. Es hat mich dazu inspiriert (vorsichtig mit den Backticks)

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

Dies kann in bash selbst erfolgen, wenn Sie die Kontrolle über das Format der Konfigurationsdatei haben. Sie müssen lediglich die Konfigurationsdatei als Quelle (".") Angeben, anstatt sie unterzubringen. Dadurch wird sichergestellt, dass die Variablen im Kontext der aktuellen Shell erstellt werden (und weiterhin vorhanden sind) und nicht in der Subshell (in der die Variable verschwindet, wenn die Subshell beendet wird).

$ 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

Wenn Ihre Konfigurationsdatei kein Shell-Skript sein kann, können Sie sie einfach 'kompilieren', bevor Sie sie ausführen (die Kompilierung hängt von Ihrem Eingabeformat ab).

$ 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

In Ihrem speziellen Fall können Sie Folgendes verwenden:

$ 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

Dann leite die Ausgabe von go.bash nach MySQL und voila, hoffentlich zerstörst du deine Datenbank nicht :-).

1
paxdiablo

Hier ist eine Möglichkeit, die Shell zu veranlassen, die Ersetzung für Sie vorzunehmen, als ob der Inhalt der Datei stattdessen in doppelte Anführungszeichen gesetzt würde.

Am Beispiel von template.txt mit Inhalten:

The number is ${i}
The Word is ${Word}

Die folgende Zeile veranlasst die Shell, den Inhalt von template.txt zu interpolieren und das Ergebnis in standard out zu schreiben.

i='1' Word='dog' sh -c 'echo "'"$(cat template.txt)"'"'

Erläuterung:

  • i und Word werden als Umgebungsvariablen an die Ausführung von sh übergeben.
  • sh führt den Inhalt des übergebenen Strings aus.
  • Nebeneinander geschriebene Zeichenfolgen werden zu einer Zeichenfolge. Diese Zeichenfolge lautet:
    • 'echo "' + "$(cat template.txt)" + '"'
  • Da die Ersetzung zwischen " Erfolgt, wird "$(cat template.txt)" zur Ausgabe von cat template.txt.
  • Der von sh -c Ausgeführte Befehl lautet also:
    • echo "The number is ${i}\nThe Word is ${Word}",
    • dabei sind i und Word die angegebenen Umgebungsvariablen.
1
Apriori