Saya ingin menyalurkan output file "template" ke MySQL, file yang memiliki variabel seperti ${dbName}
diselingi. Apa utilitas baris perintah untuk mengganti instance ini dan membuang output ke output standar?
Saya ingin menyalurkan output file "template" ke MySQL, file yang memiliki variabel seperti ${dbName}
diselingi. Apa utilitas baris perintah untuk mengganti instance ini dan membuang output ke output standar?
Jawaban:
Sed !
Template.txt yang diberikan:
Jumlahnya adalah $ {i} Kata itu adalah $ {kata}
kita hanya harus mengatakan:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
Terima kasih kepada Jonathan Leffler atas tipnya untuk meloloskan banyak -e
argumen ke sed
permohonan yang sama .
cat
. Yang Anda butuhkan hanyalah sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
.
sed
akan mengharapkan teks yang lolos, yang merepotkan.
Berikut ini adalah solusi dari yottatsa pada pertanyaan serupa yang hanya melakukan penggantian untuk variabel seperti $ VAR atau $ {VAR}, dan merupakan one-liner singkat
i=32 word=foo envsubst < template.txt
Tentu saja jika saya dan kata ada di lingkungan Anda, maka itu adil
envsubst < template.txt
Di Mac saya sepertinya diinstal sebagai bagian dari gettext dan dari MacGPG2
Berikut ini adalah peningkatan solusi dari mogsie pada pertanyaan yang sama, solusi saya tidak mengharuskan Anda untuk mengawal tanda kutip ganda, mogsie tidak, tapi itu adalah satu liner!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
Kekuatan pada dua solusi ini adalah bahwa Anda hanya mendapatkan beberapa jenis ekspansi shell yang tidak terjadi secara normal $ ((...)), `...`, dan $ (...), meskipun backslash adalah sebuah melarikan diri karakter di sini, tetapi Anda tidak perlu khawatir bahwa parsing memiliki bug, dan itu beberapa baris baik-baik saja.
envsubst
tidak berfungsi jika utusan Anda tidak diekspor.
envsubst
, seperti namanya, hanya mengenali variabel lingkungan , bukan variabel shell . Perlu juga dicatat bahwa envsubst
ini adalah utilitas GNU , dan karena itu tidak diinstal sebelumnya atau tersedia di semua platform.
Gunakan /bin/sh
. Buat skrip shell kecil yang mengatur variabel, dan kemudian parsing templat menggunakan shell itu sendiri. Seperti itu (edit untuk menangani baris baru dengan benar):
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
perintah dalam input akan dieksekusi. Jika templatnya adalah: "kata-katanya adalah; rm -rf $ HOME" Anda akan kehilangan file.
read
perintah, seperti yang tertulis, memotong spasi spasi awal dan akhir dari setiap baris dan \
karakter 'makan' ., (C) hanya menggunakan ini jika Anda sepenuhnya percaya atau mengontrol input, karena penggantian perintah ( `…`
atau $(…)
) yang tertanam dalam input memungkinkan eksekusi perintah sewenang-wenang karena penggunaan eval
. Akhirnya, ada kemungkinan kecil bahwa echo
kesalahan awal baris untuk salah satu opsi baris perintah.
Saya memikirkan hal ini lagi, mengingat minat baru-baru ini, dan saya pikir alat yang awalnya saya pikirkan adalah m4
, prosesor makro untuk autotool. Jadi alih-alih variabel yang saya tentukan sebelumnya, Anda akan menggunakan:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubst
untuk penggantian / templating variabel penggunaan sederhana ini, sebagaimana disebutkan dalam jawaban lain. m4
adalah alat yang hebat, tetapi ini adalah preprocessor besar-besaran dengan lebih banyak fitur dan karenanya kompleksitas yang mungkin tidak diperlukan jika Anda hanya ingin mengganti beberapa variabel.
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
`…`
atau $(…)
) yang tertanam dalam input memungkinkan eksekusi perintah arbitrer karena penggunaan eval
, dan eksekusi langsung kode shell karena penggunaan source
. Juga, tanda kutip ganda dalam input secara diam-diam dibuang, dan echo
bisa keliru awal baris untuk salah satu opsi baris perintah.
Inilah fungsi Bash yang kuat yang - meskipun digunakan eval
- harus aman digunakan.
Semua ${varName}
referensi variabel dalam teks input diperluas berdasarkan variabel shell panggilan.
Tidak ada lagi yang diperluas: baik referensi variabel yang namanya tidak termasuk dalam {...}
(seperti $varName
), atau pergantian perintah ( $(...)
dan sintaksis warisan `...`
), atau pergantian aritmatika ( $((...))
dan sintaksis warisan $[...]
).
Untuk memperlakukan $
sebagai literal, \
-escape itu; misalnya:\${HOME}
Perhatikan bahwa input hanya diterima melalui stdin .
Contoh:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
Kode sumber fungsi:
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
}
Fungsi ini mengasumsikan bahwa tidak ada 0x1
, 0x2
, 0x3
, dan 0x4
karakter kontrol yang hadir dalam input, karena mereka chars. digunakan secara internal - karena fungsi memproses teks , itu harus menjadi asumsi yang aman.
eval
pun cukup aman untuk digunakan.
"
dengan benar!)
${FOO:-bar}
atau hanya mengeluarkan sesuatu jika sudah disetel - ${HOME+Home is ${HOME}}
. Saya menduga dengan sedikit ekstensi itu juga bisa mengembalikan kode keluar untuk variabel yang hilang ${FOO?Foo is missing}
tetapi saat ini tidak tldp.org/LDP/abs/html/parameter-substitution.html memiliki daftar ini jika itu membantu
Buat rendertemplate.sh
:
#!/usr/bin/env bash
eval "echo \"$(cat $1)\""
Dan template.tmpl
:
Hello, ${WORLD}
Goodbye, ${CHEESE}
Render template:
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
$(rm -rf ~)
, Anda menjalankannya sebagai kode.
eval "echo \"$(cat $1)\""
Bagus sekali!
inilah solusi saya dengan perl berdasarkan jawaban sebelumnya, menggantikan variabel lingkungan:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
Jika Anda terbuka untuk menggunakan Perl , itu akan menjadi saran saya. Meskipun mungkin ada beberapa ahli sed dan / atau AWK yang mungkin tahu cara melakukan ini lebih mudah. Jika Anda memiliki pemetaan yang lebih kompleks dengan lebih dari sekadar dbName untuk pengganti Anda, Anda dapat memperpanjang ini dengan mudah, tetapi Anda mungkin juga memasukkannya ke skrip Perl standar pada saat itu.
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
Skrip Perl pendek untuk melakukan sesuatu yang sedikit lebih rumit (menangani beberapa tombol):
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
Jika Anda memberi nama skrip di atas sebagai skrip pengganti, skrip tersebut dapat digunakan sebagai berikut:
replace-script < yourfile | mysql
Berikut adalah cara untuk membuat shell melakukan substitusi untuk Anda, seolah-olah isi file tersebut diketik di antara tanda kutip ganda.
Menggunakan contoh template.txt dengan konten:
The number is ${i}
The word is ${word}
Baris berikut akan menyebabkan shell menginterpolasi isi template.txt dan menulis hasilnya ke standar.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
Penjelasan:
i
dan word
diteruskan sebagai variabel lingkungan dicopot ke pelaksanaan sh
.sh
mengeksekusi isi dari string yang dilewatkan.echo "
' + " $(cat template.txt)
" + ' "
'"
, " $(cat template.txt)
" menjadi output daricat template.txt
.sh -c
menjadi:
echo "The number is ${i}\nThe word is ${word}"
,i
dan word
merupakan variabel lingkungan yang ditentukan.'$(rm -rf ~)'$(rm -rf ~)
kutipan literal dalam file templat akan cocok dengan yang Anda tambahkan sebelum perluasannya.
'$(echo a)'$(echo a)
. Itu menghasilkan 'a'a
. Hal utama yang terjadi adalah bahwa bagian echo a
dalam pertama '
sedang dievaluasi, yang mungkin bukan yang Anda harapkan sejak itu '
, tetapi perilaku yang sama seperti termasuk '
dalam "
string yang dikutip.
"
dikutip oleh string (termasuk $(...)
) adalah intinya.
${varname}
, bukan yang lain, ekspansi risiko keamanan yang lebih tinggi.
echo "
, diikuti oleh string yang dikutip ganda dengan rangkaian literal template.txt
, diikuti oleh string literal lain "
, semua disatukan menjadi argumen tunggal yang diteruskan sh -c
. Anda benar bahwa '
tidak dapat dicocokkan (karena dikonsumsi oleh kulit terluar daripada diteruskan ke kulit dalam), tetapi "
pasti bisa, sehingga templat yang berisi Gotcha"; rm -rf ~; echo "
dapat dieksekusi.
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
sebagai read
perintah, jika tidak, Anda akan menghapus spasi spasi awal dan akhir dari setiap baris input. Juga, echo
bisa keliru awal baris untuk salah satu opsi baris perintah, jadi lebih baik digunakan printf '%s\n'
. Akhirnya, lebih aman untuk mengutip ganda ${1}
.
Saya akan menyarankan menggunakan sesuatu seperti Sigil : https://github.com/gliderlabs/sigil
Ini dikompilasi ke biner tunggal, jadi sangat mudah untuk menginstal pada sistem.
Maka Anda dapat melakukan satu-liner sederhana seperti berikut:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
Ini jauh lebih aman daripada eval
dan lebih mudah menggunakan regex ataused
cat
dan menggunakan <my-file.conf.template
sebagai gantinya Anda memberikan sigil
pegangan file nyata daripada FIFO.
Saya menemukan utas ini sambil bertanya-tanya hal yang sama. Itu mengilhami saya untuk ini (hati-hati dengan backticks)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
$(cat file)
adalah$(< file)
eval echo "\"$(cat FILE)\""
tetapi itu mungkin masih gagal karena tanda kutip ganda pada input dibuang.
`…`
atau $(…)
) yang tertanam dalam input memungkinkan eksekusi perintah sewenang-wenang karena penggunaan eval
.
Banyak pilihan di sini, tapi kupikir aku akan melemparkan milikku di atas tumpukan. Berbasis perl, hanya variabel target dari formulir $ {...}, yang akan memproses file sebagai argumen dan menampilkan file yang dikonversi di stdout:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
Tentu saja saya bukan orang yang benar-benar perl, jadi bisa saja ada kesalahan fatal (bekerja untuk saya).
Env::import();
- mengimpor tersirat oleh use
. Juga, saya sarankan untuk tidak membangun seluruh output dalam memori terlebih dahulu: cukup gunakan print;
alih-alih $text .= $_;
di dalam loop, dan lepaskan perintah post-loop print
.
Ini dapat dilakukan dalam bash sendiri jika Anda memiliki kontrol format file konfigurasi. Anda hanya perlu sumber (".") File konfigurasi daripada subshell itu. Itu memastikan variabel dibuat dalam konteks shell saat ini (dan terus ada) daripada subshell (di mana variabel menghilang ketika subshell keluar).
$ 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
Jika file config Anda tidak bisa berupa skrip shell, Anda bisa 'mengompilasinya' sebelum menjalankannya (kompilasi tergantung pada format input Anda).
$ 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
Dalam kasus spesifik Anda, Anda dapat menggunakan sesuatu seperti:
$ 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
Kemudian kirimkan output go.bash ke MySQL dan voila, semoga Anda tidak akan menghancurkan database Anda :-).
go.bash
), Anda salah paham - mereka bukan bagian dari solusi, mereka hanya cara untuk menunjukkan bahwa variabel sedang diatur dengan benar.
Anda akan menginginkan sesuatu yang lebih kuat daripada saran saat ini karena sementara mereka bekerja untuk kasus penggunaan terbatas Anda (untuk saat ini), mereka tidak akan cukup untuk situasi yang lebih kompleks.
Anda membutuhkan penyaji yang lebih baik. Anda membutuhkan penyaji terbaik. Anda membutuhkan Yang Renderest!
Template.txt yang diberikan:
Halo, {{person}}!
Lari:
$ person = Bob ./render template.txt
Dan Anda akan melihat hasilnya
Halo, Bob!
Tulis ke file dengan mengarahkan stdout ke file:
$ person = Bob ./render template.txt> rendered.txt
Dan jika Anda membuat skrip yang memiliki variabel $ {} yang tidak ingin Anda interpolasi, The Renderest membuat Anda dilindungi tanpa harus melakukan hal lain!
Lanjutkan dan dapatkan salinan Anda di https://github.com/relaxdiego/renderest