Chcę przesłać dane wyjściowe pliku „szablonu” do MySQL, plik zawierający zmienne, takie jak ${dbName}przeplatane. Jakie narzędzie wiersza poleceń zastępuje te wystąpienia i zrzuca dane wyjściowe na standardowe wyjście?
Chcę przesłać dane wyjściowe pliku „szablonu” do MySQL, plik zawierający zmienne, takie jak ${dbName}przeplatane. Jakie narzędzie wiersza poleceń zastępuje te wystąpienia i zrzuca dane wyjściowe na standardowe wyjście?
Odpowiedzi:
Sed !
Podany plik template.txt:
Numer to $ {i}
Słowo to $ {word}
musimy tylko powiedzieć:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
Podziękowania dla Jonathana Lefflera za wskazówkę dotyczącą przekazywania wielu -eargumentów do tego samego sedwywołania.
cat. Wszystko czego potrzebujesz to sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text.
sedoczekuje tekstu ucieczki, co jest kłopotliwe.
Oto rozwiązanie od yottatsy na podobne pytanie, które zastępuje tylko zmienne, takie jak $ VAR lub $ {VAR}, i jest krótkim, jednowierszowym
i=32 word=foo envsubst < template.txt
Oczywiście, jeśli ja i słowo są w twoim środowisku, to jest po prostu
envsubst < template.txt
Na moim Macu wygląda na to, że został zainstalowany jako część gettext i z MacGPG2
Oto ulepszenie rozwiązania z mogsie na podobne pytanie, moje rozwiązanie nie wymaga eskalowania podwójnych cudzysłowów, tak jak mogsie, ale jego jest jeden liniowiec!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
Moc na tych dwóch rozwiązań jest to, że można dostać tylko kilka rodzajów rozszerzeń powłoki, które nie występują normalnie $ ((...)), `...` i $ (...), choć backslash jest tutaj znak ucieczki, ale nie musisz się martwić, że parsowanie ma błąd, a wiele linii jest w porządku.
envsubstnie działa, jeśli twoje envars nie są eksportowane.
envsubstjak sama nazwa wskazuje, rozpoznaje tylko zmienne środowiskowe , a nie zmienne powłoki . Warto również zauważyć, że envsubstjest to narzędzie GNU , a zatem nie jest preinstalowane ani dostępne na wszystkich platformach.
Posługiwać się /bin/sh . Utwórz mały skrypt powłoki, który ustawia zmienne, a następnie przeanalizuj szablon przy użyciu samej powłoki. Tak (edytuj, aby poprawnie obsługiwać znaki nowej linii):
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
bashpolecenia wprowadzone na wejściu zostaną wykonane. Jeśli szablon to: "the words is; rm -rf $ HOME" stracisz pliki.
readpolecenie, jak napisano, przycina początkowe i końcowe białe spacje z każdej linii i ` \ ` zjada '' znaki., (C) użyj tego tylko wtedy, gdy w pełni ufają lub kontrolują dane wejściowe, ponieważ podstawienia komend ( `…` lub $(…)) osadzone w danych wejściowych pozwalają na wykonywanie dowolnych poleceń z powodu użycia eval. Wreszcie, istnieje niewielka szansa, że echopoczątek wiersza pomylisz z jedną z opcji wiersza poleceń.
Myślałem o tym ponownie, biorąc pod uwagę niedawne zainteresowanie i myślę, że narzędziem, o którym pierwotnie myślałem, był m4procesor makr dla automatycznych narzędzi. Więc zamiast zmiennej, którą pierwotnie określiłem, użyjesz:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubstdo tego prostego użycia zastępowania zmiennych / szablonów, jak wspomniano w innych odpowiedziach. m4to świetne narzędzie, ale jest to pełnowartościowy preprocesor z dużo większą liczbą funkcji, a tym samym złożonością, która może nie być potrzebna, jeśli chcesz po prostu zastąpić niektóre zmienne.
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
`…` lub $(…)) osadzone w danych wejściowych pozwalają na wykonywanie dowolnych poleceń w wyniku użycia evali bezpośrednie wykonanie kodu powłoki w wyniku użycia source. Ponadto podwójne cudzysłowy w danych wejściowych są po cichu odrzucane i echomogą pomylić początek wiersza z jedną z opcji wiersza poleceń.
Oto solidna funkcja Bash, która - pomimo użycia eval- powinna być bezpieczna w użyciu.
Wszystkie ${varName}odwołania do zmiennych w tekście wejściowym są interpretowane na podstawie zmiennych wywołującej powłoki.
Nic innego nie jest rozwijane: ani odwołania do zmiennych, których nazwy nie są zawarte w {...}(takie jak $varName), ani podstawienia poleceń ( $(...)i starsza składnia `...`), ani podstawienia arytmetyczne ( $((...))i starsza składnia$[...] ).
Aby traktować a $jako dosłowne, \-urzuć go; na przykład:\${HOME}
Należy pamiętać, że dane wejściowe są akceptowane tylko przez stdin .
Przykład:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
Kod źródłowy funkcji:
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
}
Funkcja zakłada, że żadna 0x1, 0x2, 0x3, i 0x4znaki kontrolne są obecne w danych wejściowych, ponieważ te znaki. są używane wewnętrznie - ponieważ funkcja przetwarza tekst , powinno to być bezpieczne założenie.
evaljest całkiem bezpieczny w użyciu.
"poprawnie!)
${FOO:-bar}lub wyprowadzić coś tylko wtedy, gdy jest ustawione - ${HOME+Home is ${HOME}}. Podejrzewam, że z małym rozszerzeniem może również zwracać kody wyjścia dla brakujących zmiennych, ${FOO?Foo is missing}ale obecnie tldp.org/LDP/abs/html/parameter-substitution.html ma ich listę, jeśli to pomoże
Utwórz rendertemplate.sh:
#!/usr/bin/env bash
eval "echo \"$(cat $1)\""
Oraz template.tmpl:
Hello, ${WORLD}
Goodbye, ${CHEESE}
Renderuj szablon:
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
$(rm -rf ~), uruchamiasz to jako kod.
eval "echo \"$(cat $1)\"" Działa świetnie !
oto moje rozwiązanie z perlem na podstawie poprzedniej odpowiedzi, zastępuje zmienne środowiskowe:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
Jeśli jesteś otwarty na używanie Perla , to byłaby moja sugestia. Chociaż prawdopodobnie są niektórzy eksperci sed i / lub AWK, którzy prawdopodobnie wiedzą, jak to zrobić znacznie łatwiej. Jeśli masz bardziej złożone mapowanie z więcej niż tylko dbName dla swoich zamienników, możesz to dość łatwo rozszerzyć, ale równie dobrze możesz równie dobrze umieścić je w standardowym skrypcie Perla w tym momencie.
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
Krótki skrypt Perla, który robi coś bardziej skomplikowanego (obsługuje wiele kluczy):
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
Jeśli nazwiesz powyższy skrypt jako skrypt zastępujący, można go następnie użyć w następujący sposób:
replace-script < yourfile | mysql
Oto sposób, aby powłoka wykonała podstawienie za Ciebie, tak jakby zawartość pliku była zamiast tego wpisywana w cudzysłowy.
Na przykładzie template.txt z zawartością:
The number is ${i}
The word is ${word}
Następujący wiersz spowoduje, że powłoka interpoluje zawartość pliku template.txt i zapisuje wynik do standardowego wyjścia.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
Wyjaśnienie:
ii wordsą przekazywane jako zmienne środowiskowe ograniczone do wykonania sh.sh wykonuje zawartość przekazanego ciągu.echo "' + " $(cat template.txt)" + ' "'", " $(cat template.txt)" staje się wynikiemcat template.txt .sh -cstaje się:
echo "The number is ${i}\nThe word is ${word}",ii wordsą określonymi zmiennymi środowiskowymi.'$(rm -rf ~)'$(rm -rf ~)dosłowne cudzysłowy w pliku szablonu będą pasowały do tych, które dodałeś przed jego rozwinięciem.
'$(echo a)'$(echo a). Produkuje 'a'a. Najważniejsze, co się dzieje, jest to, że pierwszy element echo awewnątrz elementu 'jest oceniany, co może nie być tym, czego się spodziewasz, ponieważ jest w nim ', ale zachowuje się tak samo, jak 'w przypadku umieszczania w "cudzysłowie.
"Chodzi o rozwinięcie czegokolwiek w cudzysłowie (włącznie $(...)).
${varname}inne rozszerzenia o wyższym ryzyku bezpieczeństwa, a nie inne rozszerzenia.
echo ", po którym następuje podwójny cudzysłów z ciągiem literału template.txt, po którym następuje kolejny ciąg literału ", a wszystko to jest połączone w pojedynczy argument przekazywany do sh -c. Masz rację, że 'nie można dopasować (ponieważ został zużyty przez zewnętrzną powłokę, a nie przekazany do wewnętrznej), ale z "pewnością może, więc szablon zawierający Gotcha"; rm -rf ~; echo "może zostać wykonany.
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; dojako readpolecenia, w przeciwnym razie usuniesz początkowe i końcowe spacje z każdego wiersza wprowadzania. Ponadto echomoże pomylić początek wiersza z jedną z opcji wiersza poleceń, więc lepiej jest użyć printf '%s\n'. Wreszcie, bezpieczniej jest podwójne cytowanie ${1}.
Sugerowałbym użycie czegoś takiego jak Sigil : https://github.com/gliderlabs/sigil
Jest skompilowany do pojedynczego pliku binarnego, więc jest niezwykle łatwy do zainstalowania w systemach.
Następnie możesz wykonać prostą jedną linijkę, taką jak następujące:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
Jest to znacznie bezpieczniejsze evali łatwiejsze niż użycie wyrażenia regularnego lubsed
cati używać <my-file.conf.templatezamiast tego, aby dać sigilprawdziwy uchwyt pliku zamiast FIFO.
Znalazłem ten wątek, zastanawiając się nad tym samym. Zainspirowało mnie to do tego (uważaj na lewe napisy)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
$(cat file)$(< file)
eval echo "\"$(cat FILE)\""ale może to nadal być niewystarczające, ponieważ podwójne cudzysłowy w danych wejściowych są odrzucane.
`…` lub $(…)) wbudowane w dane wejściowe pozwalają na wykonywanie dowolnych poleceń z powodu użycia eval.
Sporo możliwości wyboru, ale pomyślałem, że rzucę swój na stos. Jest oparty na perlu, celuje tylko w zmienne w postaci $ {...}, pobiera plik do przetworzenia jako argument i wyprowadza przekonwertowany plik na standardowe wyjście:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
Oczywiście nie jestem osobą perlową, więc łatwo może być fatalna wada (chociaż dla mnie działa).
Env::import();linię - import jest implikowany przez use. Sugeruję również, aby najpierw nie gromadzić całego wyjścia w pamięci: po prostu użyj print;zamiast $text .= $_;wewnątrz pętli i porzuć printpolecenie pętli .
Można to zrobić w samym bashu, jeśli masz kontrolę nad formatem pliku konfiguracyjnego. Musisz tylko pozyskać („.”) Plik konfiguracyjny, a nie podpowłokę. Zapewnia to, że zmienne są tworzone w kontekście bieżącej powłoki (i nadal istnieją), a nie w podpowłoce (gdzie zmienna znika po zamknięciu podpowłoki).
$ 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
Jeśli twój plik konfiguracyjny nie może być skryptem powłoki, możesz go po prostu „skompilować” przed wykonaniem (kompilacja zależy od formatu wejściowego).
$ 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
W swoim konkretnym przypadku możesz użyć czegoś takiego:
$ 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
Następnie prześlij wyjście go.bash do MySQL i voila, miejmy nadzieję, że nie zniszczysz swojej bazy danych :-).
go.bash), Masz niewłaściwy koniec patyka - nie są one częścią rozwiązania, są tylko sposobem pokazania, że zmienne są ustawione prawidłowo.
Będziesz chciał czegoś solidniejszego niż obecne sugestie, ponieważ chociaż działają one w twoim (na razie) ograniczonym przypadku użycia, nie wystarczą w bardziej złożonych sytuacjach.
Potrzebujesz lepszego renderera. Potrzebujesz najlepszego renderera. Potrzebujesz Renderest!
Podany plik template.txt:
Cześć osobo}}!
Biegać:
$ person = Bob ./render template.txt
Zobaczysz wynik
Cześć Bob!
Zapisz go do pliku, przekierowując standardowe wyjście do pliku:
$ person = Bob ./render template.txt> rendering.txt
A jeśli zdarzy ci się renderować skrypt zawierający zmienne $ {}, których nie chcesz interpolować, The Renderest zapewni Ci ochronę bez konieczności robienia czegokolwiek innego!
Kontynuuj i zdobądź swoją kopię na https://github.com/relaxdiego/renderest