Вопрос

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

Это было полезно?

Решение

Sed !

Данный template.txt:

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

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

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

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

Другие советы

Update

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

i=32 word=foo envsubst < template.txt

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

envsubst < template.txt

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

Старый ответ

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

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

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

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

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

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

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

шаблон.txt

Variable 1 value: ${var1}
Variable 2 value: ${var2}

данные.sh

#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"

парсер.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 шаблон.txt анализируемый_файл.txt

анализируемый_файл.txt

Variable 1 value: value 1
Variable 2 value: value 2

вот мое решение с Perl, основанное на предыдущем ответе, заменяет переменные среды:

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

Вот надежная функция 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 во входных данных присутствуют управляющие символы, поскольку эти символы.используются внутри — поскольку функция обрабатывает текст, это должно быть безопасным предположением.

Если вы открыты для использования 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/\$\{

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

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

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

replace-script < yourfile | mysql

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

<*>\}/$replace{

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

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

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

<*>

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

<*>}/g for keys %replace; print $buf;

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

<*>

Создать 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

файл.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.

скрипт.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

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

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

Затем вы можете сделать простой однострочный текст, как показано ниже:

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

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

Я нашел эту ветку, удивляясь тому же. Это вдохновило меня на это (осторожно с галочкой)

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

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

use Env;
Env::import();

while(<>) { 

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

<*>

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

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

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

<*>

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

; } print "$text";

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

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

$ 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 '^

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

$ 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 и вуаля, надеюсь, вы не уничтожите свою базу данных: -).

| 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

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

<*>

Затем перенаправьте вывод go.bash в 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 являются указанными переменными среды.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top