Я хочу направить вывод файла «шаблона» в MySQL, файл, имеющий переменные, такие как ${dbName}
вкрапленные. Что такое утилита командной строки для замены этих экземпляров и вывода вывода на стандартный вывод?
Я хочу направить вывод файла «шаблона» в MySQL, файл, имеющий переменные, такие как ${dbName}
вкрапленные. Что такое утилита командной строки для замены этих экземпляров и вывода вывода на стандартный вывод?
Ответы:
Сед !
Данный шаблон.txt:
Число: $ {i} Слово это $ {слово}
мы просто должны сказать:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
Спасибо Джонатану Леффлеру за подсказку о передаче нескольких -e
аргументов в один sed
вызов.
cat
. Все, что вам нужно, это sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
.
sed
будет ожидать экранированный текст, который является проблемой.
Вот решение от 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
Сила этих двух решений является то , что вы получите только несколько типов расширений оболочки , которые не встречаются обычно $ ((...)), `...` и $ (...), хотя обратный слэш является здесь есть экранирующий символ, но вам не нужно беспокоиться о том, что при разборе есть ошибка, и он отлично справляется с несколькими строками.
envsubst
не работает, если ваши envars не экспортируются.
envsubst
Как следует из названия, он распознает только переменные окружения , а не переменные оболочки . Стоит также отметить, что envsubst
это утилита GNU , поэтому она не предустановлена и не доступна на всех платформах.
Использование /bin/sh
. Создайте небольшой скрипт оболочки, который устанавливает переменные, а затем проанализируйте шаблон с помощью самой оболочки. Вот так (отредактируйте, чтобы правильно обрабатывать новые строки):
the number is ${i}
the word is ${word}
#!/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
bash
команды на входе будут выполнены. Если шаблон: «the words is; rm -rf $ HOME», вы потеряете файлы.
read
команда, как написано, обрезает начальные и конечные пробелы в каждой строке и «ест» \
символы. (В) используйте это, только если вы полностью доверять или контролировать ввод, потому что подстановки команд ( `…`
или $(…)
), встроенные во ввод, позволяют выполнять произвольные команды из-за использования eval
. Наконец, есть небольшая вероятность того, что echo
в начале строки будет указан один из параметров командной строки.
Я снова думал об этом, учитывая недавний интерес, и я думаю, что инструмент, о котором я первоначально думал, был m4
, макропроцессор для автоинструментов. Таким образом, вместо переменной, которую я первоначально указал, вы должны использовать:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubst
эту простую замену / использование шаблонов, как упоминалось в других ответах. m4
Это отличный инструмент, но это полноценный препроцессор с гораздо большим количеством функций и, следовательно, сложностью, которая может не потребоваться, если вы просто хотите заменить некоторые переменные.
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
`…`
или $(…)
), встроенные во ввод, позволяют выполнять произвольные команды из-за использования eval
и непосредственное выполнение кода оболочки из-за использования source
. Кроме того, двойные кавычки во входных данных незаметно отбрасываются, и они echo
могут ошибочно принять начало строки за один из параметров командной строки.
Вот надежная функция Bash, которая, несмотря на использованиеeval
следует использовать безопасно.
Все ${varName}
ссылки на переменные во входном тексте расширяются на основе переменных вызывающей оболочки.
Больше ничего не раскрывается: ни ссылки на переменные, имена которых не заключены в {...}
(такие как $varName
), ни подстановки команд ( $(...)
и устаревший синтаксис `...`
), ни арифметические подстановки ( $((...))
и устаревший синтаксис$[...]
).
Для того, чтобы лечить , $
как буквальные, \
экранирующий его; например:\${HOME}
Обратите внимание, что ввод принимается только через стандартный ввод .
Пример:
$ 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
управляющие символы присутствуют на входе, потому что эти символы. используются внутренне - так как функция обрабатывает текст , это должно быть безопасным допущением.
eval
это довольно безопасно для использования.
"
правильно убегая !)
${FOO:-bar}
указать значения по умолчанию для отсутствующих переменных или вывести что-то, только если оно установлено - ${HOME+Home is ${HOME}}
. Я подозреваю, что с небольшим расширением он может также возвращать коды завершения для отсутствующих переменных, ${FOO?Foo is missing}
но в настоящее время tldp.org/LDP/abs/html/parameter-substitution.html не содержит их список, если это поможет
Создать 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
$(rm -rf ~)
, вы запускаете это как код.
eval "echo \"$(cat $1)\""
Прекрасно работает !
Вот мое решение с Perl на основе предыдущего ответа, заменяет переменные среды:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
Если вы открыты для использования Perl , это мое предложение. Хотя, вероятно, есть некоторые специалисты по sed и / или AWK, которые, вероятно, знают, как сделать это намного проще. Если у вас есть более сложное сопоставление с заменой dbName для замен, вы можете довольно легко расширить это, но вы можете с таким же успехом поместить его в стандартный сценарий Perl на этом этапе.
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
Короткий Perl-скрипт для создания чего-то более сложного (обработка нескольких ключей):
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
Если вы называете вышеуказанный скрипт как replace-script, он может быть использован следующим образом:
replace-script < yourfile | mysql
Вот способ заставить оболочку выполнить за вас замену, как если бы содержимое файла вместо этого было заключено в двойные кавычки.
Используя пример template.txt с содержимым:
The number is ${i}
The word is ${word}
Следующая строка заставит оболочку интерполировать содержимое template.txt и записать результат в стандартный формат.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
Объяснение:
i
и word
передаются как переменные среды, ограниченные для выполнения sh
.sh
выполняет содержимое строки, которую он передал.echo "
' + " $(cat template.txt)
" + ' "
'"
, " $(cat template.txt)
" становится выходом cat template.txt
.sh -c
становится:
echo "The number is ${i}\nThe word is ${word}"
,i
и word
- указанные переменные среды.'$(rm -rf ~)'$(rm -rf ~)
буквенные кавычки в файле шаблона, они будут соответствовать тем, которые вы добавили перед его расширением.
'$(echo a)'$(echo a)
. Это производит 'a'a
. Главное, что происходит, - это то, echo a
что '
вычисляется первое внутри , что может не соответствовать ожидаемому, поскольку оно внутри '
, но такое же поведение, как и включение '
в "
строку в кавычках.
"
строка в кавычках (включая $(...)
) - это точка.
${varname}
, а не другие, более рискованные расширения безопасности.
echo "
разделяетесь на строку в одинарных кавычках , за которой следует строка в двойных кавычках с литеральными контекстами template.txt
, а затем другая литеральная строка "
, все из которых объединяются в один передаваемый аргумент sh -c
. Вы правы, что '
не может быть сопоставлено (поскольку оно было использовано внешней оболочкой, а не передано внутренней), но, "
безусловно, может, так что шаблон, содержащий, Gotcha"; rm -rf ~; echo "
может быть выполнен.
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
\$(date)
while IFS= read -r line; do
в качестве read
команды, в противном случае вы удалите начальные и конечные пробелы из каждой строки ввода. Кроме того, echo
может ошибочно принять начало строки за один из параметров командной строки, поэтому лучше использовать printf '%s\n'
. Наконец, безопаснее двойные кавычки ${1}
.
Я бы предложил использовать что-то вроде Sigil : https://github.com/gliderlabs/sigil
Он скомпилирован в один двоичный файл, поэтому его очень легко установить в системах.
Тогда вы можете сделать простой однострочник, как показано ниже:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
Это гораздо безопаснее, чем eval
с помощью регулярных выражений илиsed
cat
и использовать <my-file.conf.template
вместо этого, чтобы вы дали sigil
реальный дескриптор файла вместо FIFO.
Я нашел эту тему, хотя удивляюсь тому же самому. Это вдохновило меня на это (осторожно с галочкой)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
$(cat file)
это$(< file)
eval echo "\"$(cat FILE)\""
но это может все еще не соответствовать тому, что двойные кавычки во входных данных отбрасываются.
`…`
или $(…)
), встроенные во вход, позволяют выполнять произвольные команды из-за использования eval
.
Здесь много вариантов, но я решил бросить свой в кучу. Это основано на Perl, только целевые переменные вида $ {...}, принимает файл для обработки в качестве аргумента и выводит преобразованный файл на стандартный вывод:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
Конечно, я на самом деле не Perl человек, поэтому легко может быть фатальный недостаток (работает для меня, хотя).
Env::import();
строку - импорт подразумевается use
. Кроме того, я предлагаю не создавать сначала весь вывод в памяти: просто используйте print;
вместо $text .= $_;
цикла и удалите команду post-loop print
.
Это можно сделать в самом 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
Если ваш конфигурационный файл не может быть сценарием оболочки, вы можете просто «скомпилировать» его перед выполнением (компиляция зависит от вашего формата ввода).
$ 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 и вуаля, надеюсь, вы не уничтожите свою базу данных :-).
go.bash
), у вас неправильный конец - они не являются частью решения, они просто показывают, что переменные установить правильно.
Вы захотите что-то более надежное, чем текущие предложения, потому что, хотя они работают для вашего (на данный момент) варианта ограниченного использования, их будет недостаточно для более сложных ситуаций.
Вам нужен лучший рендер. Вам нужен лучший рендер. Вам нужен Renderest!
Данный шаблон.txt:
Здравствуйте, {{person}}!
Бегать:
$ person = Bob ./render template.txt
И вы увидите выход
Привет, Боб!
Запишите его в файл, перенаправив стандартный вывод в файл:
$ person = Bob ./render template.txt> rendered.txt
И если вам случится рендерить скрипт, в котором есть переменные $ {}, которые вы не хотите интерполировать, Renderest поможет вам без необходимости делать что-либо еще!
Продолжайте и получите свою копию на https://github.com/relaxdiego/renderest