Как заменить ${} заполнители в текстовом файле?

Я хочу передать вывод файла "шаблона" в MySQL, файл с переменными типа ${dbName} вкраплен. Что такое утилита командной строки для замены этих экземпляров и выгрузка вывода на стандартный вывод?

Ответ 1

Sed!

Данный файл template.txt:

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

мы просто должны сказать:

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

Спасибо Джонатану Леффлеру за подсказку передать несколько аргументов -e тому же призыву sed.

Ответ 2

Update

Вот решение от yottatsa по аналогичному вопросу, который заменяет только переменные, такие как $VAR или ${VAR}, и представляет собой короткий однострочный

i=32 word=foo envsubst < template.txt

Конечно, если я и слово находятся в вашей среде, то это просто

envsubst < template.txt

На моем Mac это похоже, что он был установлен как часть gettext и из MacGPG2

Старый ответ

Ниже приведено улучшение решения от mogsie по аналогичному вопросу. Мое решение не требует, чтобы вы эскалации двойных кавычек, mogsie, но он один лайнер!

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

Сила этих двух решений заключается в том, что вы получаете только несколько типов расширений оболочки, которые обычно не встречаются $((...)), `...` и $(...), хотя обратная косая черта здесь является escape-символом, но вам не нужно беспокоиться о том, что в синтаксическом анализе есть ошибка, и она делает несколько строк просто отлично.

Ответ 3

Используйте /bin/sh. Создайте небольшую оболочку script, которая устанавливает переменные, а затем анализирует шаблон, используя оболочку. Так же (отредактируйте правильную обработку строк перевода):

Файл template.txt:

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

Файл 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"

Вывод:

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

Ответ 4

Я думал об этом снова, учитывая недавний интерес, и я думаю, что инструмент, о котором я изначально думал, был m4, макропроцессор для autotools. Поэтому вместо переменной, которую я изначально указал, вы должны использовать:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"

Ответ 5

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

Ответ 6

здесь мое решение с perl на основе прежнего ответа заменяет переменные среды:

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

Ответ 7

Если вы открыты для использования Perl, это будет мое предложение. Хотя есть, вероятно, некоторые sed и/или AWK, которые, вероятно, знают, как сделать это намного проще. Если у вас более сложное сопоставление с более чем просто dbName для ваших замещений, вы могли бы расширить это довольно легко, но вы могли бы также добавить его в стандартный Perl script в этот момент.

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

Короткий Perl script сделать что-то немного сложнее (обрабатывать несколько ключей):

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

Если вы назвали вышеуказанный script как replace- script, его можно было бы использовать следующим образом:

replace-script < yourfile | mysql

Ответ 8

Здесь надежная Bash функция, которая, несмотря на использование eval, должна быть безопасной.

Все ссылки ${varName} переменных во входном тексте расширены на основе переменных вызывающей оболочки.

Ничего другого не раскрывается: ни ссылки на переменные, имена которых не заключены в {...} (например, $varName), ни подстановки команд ($(...) и устаревший синтаксис `...`), ни арифметические подстановки ($((...)) и устаревший синтаксис $[...]).

Чтобы обработать a $ как литерал, \ -escape it; например:. \${HOME}

Обратите внимание, что вход принимается только через stdin.

Пример:

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

Исходный код функции:

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
}

Функция предполагает, что во входном элементе присутствуют управляющие символы 0x1, 0x2, 0x3 и 0x4, потому что эти символы. используются внутри - поскольку функция обрабатывает текст, это должно быть безопасным предположением.

Ответ 9

Создать rendertemplate.sh:

#!/usr/bin/env bash

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

И template.tmpl:

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

Выделите шаблон:

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

Ответ 10

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

Ответ 11

Я бы предложил использовать что-то вроде Sigil:   https://github.com/gliderlabs/sigil

Он скомпилирован в один бинарный файл, поэтому его очень легко установить в системах.

Затем вы можете сделать простой однострочный слой следующим образом:

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

Это намного безопаснее, чем eval, и проще, используя регулярное выражение или sed

Ответ 12

Я нашел эту ветку, задаваясь вопросом то же самое. Это вдохновило меня на это (осторожно с обратными окнами)

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

Ответ 13

Здесь много вариантов, но я понял, что я брошу свою кучу. Это perl based, только целевые переменные формы ${...}, обрабатывает файл как аргумент и выводит преобразованный файл на stdout:

use Env;
Env::import();

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

print "$text";

Конечно, я на самом деле не человек perl, поэтому легко может быть фатальный недостаток (работает для меня, хотя).

Ответ 14

Это можно сделать в bash, если вы управляете форматом файла конфигурации. Вам просто нужно указать ( "." ) Файл конфигурации, а не подстроить его. Это гарантирует, что переменные создаются в контексте текущей оболочки (и продолжают существовать), а не подоболочки (где переменная исчезает, когда подоболочка выходит).

$ 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

Если ваш файл конфигурации не может быть оболочкой script, вы можете просто "скомпилировать" его перед выполнением (компиляция зависит от вашего формата ввода).

$ 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

В вашем конкретном случае вы можете использовать что-то вроде:

$ 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

Затем подключите вывод go.bash к MySQL и voila, надеюсь, вы не уничтожите свою базу данных: -).