Я хочу передать вывод файла "шаблона" в 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, надеюсь, вы не уничтожите свою базу данных: -).