Bir "şablon" dosyasının çıktısını MySQL, boru ${dbName}
serpiştirilmiş gibi değişkenlere sahip olmak istiyorum . Bu örnekleri değiştirmek ve çıktıyı standart çıktıya dökmek için komut satırı yardımcı programı nedir?
Bir "şablon" dosyasının çıktısını MySQL, boru ${dbName}
serpiştirilmiş gibi değişkenlere sahip olmak istiyorum . Bu örnekleri değiştirmek ve çıktıyı standart çıktıya dökmek için komut satırı yardımcı programı nedir?
Yanıtlar:
Sed !
Verilen template.txt:
Sayı $ {i} Kelime $ {word}
sadece şunu söylemeliyiz:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
Bahşişin -e
aynı sed
çağrıyı birden fazla tartışmaya aktarması için Jonathan Leffler'a teşekkürler .
cat
. Tek ihtiyacınız olan şey sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
.
sed
bir güçlük olan kaçan bir metin beklenir.
İşte benzer bir soruda yottatsa'dan sadece $ VAR veya $ {VAR} gibi değişkenlerin yerini alan ve kısa bir tek satırlık bir çözüm
i=32 word=foo envsubst < template.txt
Tabii ben ve kelime çevrenizdeyse, o zaman sadece
envsubst < template.txt
O bir parçası olarak yüklendiği gibi benim Mac'te görünüyor gettext ve gelen MacGPG2
İşte benzer bir soru üzerinde mogsie'den çözümde bir iyileştirme , benim çözümüm çift tırnak, esnaf gerektirmez, mogsie yapar, ama onun bir astar!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
Bu iki çözümler üzerinde güç ters eğik çizgi gerçi sadece, (...) meydana gelmez kabuk yorumlarından birkaç türde normalde $ ((...)), `...` almak ve $ olmasıdır olan bir kaçış karakteri burada, ancak ayrıştırma bir hata var endişelenmenize gerek yok ve birden çok satır gayet iyi yapıyor.
envsubst
Envarlarınız ihraç edilmezse çıplak işe yaramıyor.
envsubst
, adından da anlaşılacağı gibi, kabuk değişkenlerini değil , yalnızca ortam değişkenlerini tanır . Ayrıca , bir GNU yardımcı programı olduğunu ve bu nedenle tüm platformlara önceden yüklenmemiş veya mevcut olmadığını belirtmek gerekir . envsubst
Kullanın /bin/sh
. Değişkenleri ayarlayan küçük bir kabuk komut dosyası oluşturun ve ardından kabuğun kendisini kullanarak şablonu ayrıştırın. Bunun gibi (yeni satırları doğru işlemek için düzenleyin):
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
komut yürütülür. Şablon: "kelimeler; rm -rf $ HOME" ise dosyaları kaybedersiniz.
read
komut, yazıldığı gibi, her satırdan baştaki ve sondaki boşlukları keser ve 'yiyor' \
karakterleri., (C) bunu yalnızca tamamen girdiye güvenin veya kontrol edin, çünkü girdiye gömülü komut ikameleri ( `…`
veya $(…)
), kullanımından dolayı keyfi komutların yürütülmesine izin verir eval
. Son olarak, echo
komut satırı seçeneklerinden biri için bir satırın başlangıcında hata yapma olasılığı küçüktür .
Yakın zamandaki ilgi göz önüne alındığında, bu konuyu tekrar düşünüyordum ve ilk başta düşündüğüm aracın, m4
otoklavların makro işlemcisi olduğunu düşünüyorum . Yani başlangıçta belirttiğim değişken yerine şunu kullanırsınız:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubst
Bu basit değişken değiştirme / şablonlama kullanımı için diğer cevaplarda belirtildiği gibi kullanacağım . m4
harika bir araçtır, ancak çok daha fazla özelliğe ve karmaşıklığa sahip, sadece bazı değişkenleri değiştirmek istiyorsanız gerekli olmayabilecek tam gelişmiş bir ön işlemcidir.
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
`…`
veya $(…)
) kullanımı nedeniyle rasgele komutların eval
yürütülmesine ve kullanımından dolayı kabuk kodunun doğrudan yürütülmesine izin verir source
. Ayrıca, girişteki çift tırnak işaretleri sessizce atılır ve echo
komut satırı seçeneklerinden biri için bir satırın başlangıcında hata yapabilir.
İşte , kullanmasına rağmen - kullanımının güvenli olması gereken sağlam bir Bash işlevieval
.
${varName}
Giriş metnindeki tüm değişken referanslar, çağrılan kabuğun değişkenlerine göre genişletilir.
Başka bir şey genişletilmemiştir: ne isimleri (örneğin ) içine alınmayan değişken referanslar , ne komut ikameleri ( ve eski sözdizimi ), ne de aritmetik ikameler ( ve eski sözdizimi ).{...}
$varName
$(...)
`...`
$((...))
$[...]
A'yı $
gerçek olarak ele almak için \
-görünümü; Örneğin:\${HOME}
Girişin sadece stdin ile kabul edildiğini unutmayın .
Misal:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
İşlev kaynak kodu:
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
}
Fonksiyon hiçbir varsayar 0x1
, 0x2
, 0x3
ve 0x4
bu karakter çünkü kontrol karakterleri, giriş mevcuttur. dahili olarak kullanılır - işlev metni işlediğinden , bu güvenli bir varsayım olmalıdır.
eval
kullanımı oldukça güvenlidir.
"
düzgün kaçıyor !)
${FOO:-bar}
veya yalnızca ayarlanmışsa bir şey çıktılamanıza izin vermesidir ${HOME+Home is ${HOME}}
. Küçük bir uzantı ile eksik değişkenler için de çıkış kodları döndürebileceğinden şüpheleniyorum ${FOO?Foo is missing}
ama şu anda tldp.org/LDP/abs/html/parameter-substitution.html yardımcı oluyorsa bunların bir listesine sahip
Oluşturun rendertemplate.sh
:
#!/usr/bin/env bash
eval "echo \"$(cat $1)\""
Ve template.tmpl
:
Hello, ${WORLD}
Goodbye, ${CHEESE}
Şablonu oluştur:
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
$(rm -rf ~)
, bunu kod olarak çalıştırıyorsunuz demektir.
eval "echo \"$(cat $1)\""
Harika çalışıyor!
işte benim önceki cevaba dayanan perl ile benim çözümüm, ortam değişkenlerini değiştirir
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
Perl'i kullanmaya açıksanız , bu benim önerim olacaktır. Her ne kadar muhtemelen bunu daha kolay yapacağını bilen bazı sed ve / veya AWK uzmanları olmasına rağmen . Değiştirmeleriniz için sadece dbName'den daha karmaşık bir eşlemeniz varsa, bunu oldukça kolay bir şekilde genişletebilirsiniz, ancak bu noktada standart bir Perl betiğine de koyabilirsiniz.
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
Biraz daha karmaşık bir şey yapmak için kısa bir Perl betiği (birden fazla tuşu kullanın):
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
Yukarıdaki komut dosyasını değiştirme komut dosyası olarak adlandırırsanız, daha sonra aşağıdaki gibi kullanılabilir:
replace-script < yourfile | mysql
Kabuğun sizin için ikame yapmasını sağlamanın bir yolu, sanki dosyanın içeriği çift tırnak arasına yazılmıştır.
Template.txt örneğini içeriklerle kullanma:
The number is ${i}
The word is ${word}
Aşağıdaki satır kabuğun template.txt içeriğini enterpolasyona ve sonucu standart çıktıya yazmasına neden olacaktır.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
Açıklama:
i
ve word
ortam değişkenleri yürütülmesine atlanır olarak geçirilir sh
.sh
iletildiği dizenin içeriğini yürütür.echo "
' + " $(cat template.txt)
" + ' "
'"
, " $(cat template.txt)
" çıktısı olur cat template.txt
.sh -c
:
echo "The number is ${i}\nThe word is ${word}"
,i
ve word
belirtilen ortam değişkenleridir.'$(rm -rf ~)'$(rm -rf ~)
şablon dosyasındaki gerçek tırnaklar genişletilmeden önce eklediklerinizle eşleşir.
'$(echo a)'$(echo a)
. Üretir 'a'a
. Oluyor Önemli olan ilk olmasıdır echo a
içeride '
sen İçinde beri beklediğiniz olmayabilir, hangi değerlendirilir oluyor '
, ancak dahil aynı davranıştır '
bir de "
alıntı dize.
"
-quoted string (dahil $(...)
).
${varname}
daha yüksek güvenlik riski açılımları istemek için görüyorum .
echo "
edebi contetns ile çift tırnaklar ardından template.txt
başka değişmez dize ardından "
, tüm geçirilen tek argüman içine birleştirilmiş sh -c
. Eşleşemeyeceğiniz konusunda haklısınız '
(iç kabuğa geçmek yerine dış kabuk tarafından tüketildiğinden), ancak "
kesinlikle yapabilir, böylece içeren bir şablon Gotcha"; rm -rf ~; echo "
yürütülebilir.
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
olarak kullanmanızı öneririm read
, aksi takdirde her giriş satırından önde gelen ve sondaki boşlukları çıkarırsınız. Ayrıca, echo
komut satırı seçeneklerinden biri için bir satırın başlangıcında hata yapabilir, bu nedenle kullanmak daha iyidir printf '%s\n'
. Son olarak, çift teklif vermek daha güvenlidir ${1}
.
Sigil gibi bir şey kullanmanızı öneririm : https://github.com/gliderlabs/sigil
Tek bir ikili dosyaya derlenmiştir, bu nedenle sistemlere kurmak son derece kolaydır.
Daha sonra aşağıdaki gibi basit bir tek astar yapabilirsiniz:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
Bu, eval
regex kullanmaktan daha güvenli ve kolaydır.sed
cat
ve kullanmak daha iyidir, <my-file.conf.template
böylece sigil
FIFO yerine gerçek bir dosya tanıtıcısı verirsiniz .
Aynı şeyi merak ederken bu konuyu buldum. Bana bu konuda ilham verdi (backticks'e dikkat et)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
$(cat file)
ise$(< file)
eval echo "\"$(cat FILE)\""
ancak yine de girişteki çift tırnakların atılması nedeniyle kısa sürebilir.
`…`
veya $(…)
) , nedeniyle rasgele komutların yürütülmesine izin verir eval
.
Burada bir sürü seçenek var, ama öbek benim fırlatmak düşündüm. Perl tabanlıdır, yalnızca $ {...} biçimindeki değişkenleri hedefler, dosyayı argüman olarak işlemek için alır ve dönüştürülen dosyayı stdout'ta çıkarır:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
Tabii ki gerçekten perl insan değilim, bu yüzden kolayca ölümcül bir kusur olabilir (benim için çalışıyor olsa da).
Env::import();
Satırı bırakabilirsiniz - içe aktarma ima edilir use
. Ayrıca, önce tüm çıktıyı bellekte oluşturmamanızı öneririm: döngü içinde kullanmak print;
yerine $text .= $_;
döngü sonrası print
komutunu bırakın .
Konfigürasyon dosyası formatı kontrolünüz varsa bash'ın kendisinde yapılabilir. Yapılandırma dosyasını alt kabuk yerine kaynaklamak (".") Yapmanız yeterlidir. Bu, değişkenlerin alt kabuktan ziyade geçerli kabuk bağlamında oluşturulmasını (ve var olmaya devam etmesini) sağlar (değişken, alt kabuk çıktığında kaybolur).
$ 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
Eğer yapılandırma dosyanız bir kabuk betiği olamazsa, onu çalıştırmadan önce sadece 'derleyebilirsiniz' (derleme giriş formatınıza bağlıdır).
$ 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
Özel durumunuzda aşağıdaki gibi bir şey kullanabilirsiniz:
$ 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
Sonra go.bash çıktısını MySQL ve voila'ya aktarın, umarım veritabanınızı yok etmezsiniz :-).
go.bash
) yankı ifadesinden bahsediyorsanız , çubuğun yanlış ucuna sahipsiniz - çözümün bir parçası değiller, sadece değişkenlerin var olduğunu göstermenin bir yolu doğru şekilde ayarlayın.
Mevcut önerilerden daha sağlam bir şey isteyeceksiniz, çünkü (şimdilik) sınırlı kullanım durumunuz için çalışırken, daha karmaşık durumlar için yeterli olmayacaklardır.
Daha iyi bir oluşturucuya ihtiyacınız var. En iyi renderere ihtiyacınız var. Renderest'e ihtiyacınız var!
Verilen template.txt:
Merhaba insan}}!
Çalıştırmak:
$ person = Bob ./render template.txt
Ve çıktıyı göreceksiniz
Merhaba Bob!
Stdout'u bir dosyaya yönlendirerek bir dosyaya yazın:
$ person = Bob ./render template.txt> rendered.txt
Ve enterpolasyon yapılmasını istemediğiniz $ {} değişkenleri olan bir komut dosyası oluşturuyorsanız, Renderest başka bir şey yapmanıza gerek kalmadan sizi ele geçirdi!
Devam edin ve https://github.com/relaxdiego/renderest adresinden kopyanızı alın