Saya sedang menulis skrip untuk secara otomatis membuat file konfigurasi untuk Apache dan PHP untuk server web saya sendiri. Saya tidak ingin menggunakan GUI seperti CPanel atau ISPConfig.
Saya memiliki beberapa template file konfigurasi Apache dan PHP. Script Bash perlu membaca templat, membuat subtitle variabel dan templat keluaran diuraikan ke dalam beberapa folder. Apa cara terbaik untuk melakukannya? Saya dapat memikirkan beberapa cara. Mana yang terbaik atau mungkin ada beberapa cara yang lebih baik untuk melakukan itu? Saya ingin melakukannya dalam Bash murni (mudah dalam PHP misalnya)
1) Bagaimana cara mengganti $ {} placeholder dalam file teks?
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"
BTW, bagaimana cara mengarahkan output ke file eksternal di sini? Apakah saya perlu melarikan diri sesuatu jika variabel berisi, katakanlah, tanda kutip?
2) Menggunakan cat & sed untuk mengganti setiap variabel dengan nilainya:
Template.txt yang diberikan:
The number is ${i}
The word is ${word}
Perintah:
cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"
Tampak buruk bagi saya karena kebutuhan untuk melarikan diri banyak simbol yang berbeda dan dengan banyak variabel garisnya akan terlalu panjang.
Bisakah Anda memikirkan beberapa solusi elegan dan aman lainnya?
sumber
Jawaban:
Anda bisa menggunakan ini:
untuk mengganti semua
${...}
string dengan variabel lingkungan yang sesuai (jangan lupa untuk mengekspornya sebelum menjalankan skrip ini).Untuk bash murni, ini harus berfungsi (dengan asumsi variabel tidak mengandung string $ {...}):
. Solusi yang tidak hang jika RHS mereferensikan beberapa variabel yang mereferensikan dirinya:
PERINGATAN : Saya tidak tahu cara menangani input dengan benar dengan NUL di bash atau mempertahankan jumlah trailing newlines. Varian terakhir disajikan sebagaimana adanya karena input biner dari shell: "love":
read
akan menafsirkan garis miring terbalik.read -r
tidak akan mengartikan garis miring terbalik, tetapi masih akan menghapus baris terakhir jika tidak diakhiri dengan baris baru."$(…)"
akan menghapus sebanyak mungkin baris baru yang ada, jadi saya akhiri…
dengan; echo -n a
dan menggunakanecho -n "${line:0:-1}"
: ini akan menghapus karakter terakhir (yanga
) dan mempertahankan baris baru sebanyak yang ada di input (termasuk no).sumber
[^}]
ke[A-Za-Z_][A-Za-z0-9_]
dalam versi bash untuk mencegah shell melampaui substitusi yang ketat (misalnya jika mencoba untuk memproses${some_unused_var-$(rm -rf $HOME)}
).$&
dalam solusi perl untuk""
: pertama${...}
tidak tersentuh jika gagal untuk menggantikan, kedua menggantikannya dengan string kosong.while
loop membaca baris terakhir bahkan jika itu tidak diakhiri oleh baris baru, gunakanwhile read -r line || [[ -n $line ]]; do
. Selain itu,read
command strip Anda memimpin dan mengikuti spasi putih dari setiap baris; untuk menghindarinya, gunakanwhile IFS= read -r line || [[ -n $line ]]; do
\
-menghilangkan mereka).Mencoba
envsubst
sumber
envsubst
tidak diperlukan ketika menggunakan heredoc karena bash memperlakukan heredoc sebagai string yang dikutip ganda secara literal dan menginterpolasikan variabel di dalamnya. Ini adalah pilihan yang bagus ketika Anda ingin membaca templat dari file lain. Pengganti yang baik untuk yang jauh lebih rumitm4
.envsubst
adalah utilitas gettext GNU, dan sebenarnya tidak terlalu kuat (karena gettext dimaksudkan untuk melokalisasi pesan manusia). Yang paling penting, ia tidak mengenali penggantian $ {VAR} backslash-lolos (jadi Anda tidak dapat memiliki templat yang menggunakan substitusi $ VAR saat runtime, seperti skrip shell atau file conf Nginx). Lihat jawaban saya untuk solusi yang menangani lolos backslash.<<"EOF"
, yang tidak menginterpolasi variabel (terminator yang dikutip seperti tanda kutip tunggal heredocs).cat template.txt | envsubst
envsubst baru bagi saya. Fantastis.
Sebagai catatan, menggunakan heredoc adalah cara yang bagus untuk membuat templat file conf.
sumber
envsubst
karena itu menyelamatkan saya dari tambahanapt-get install gettext-base
di Dockerfile sayaSaya setuju dengan menggunakan sed: ini adalah alat terbaik untuk mencari / mengganti. Inilah pendekatan saya:
sumber
-i
opsi (edit file di tempat) yang mirip dengan opsi perl . Periksa halaman manual untuk sed Anda .Saya pikir eval bekerja dengan sangat baik. Ini menangani template dengan linebreak, spasi putih, dan segala macam hal bash. Jika Anda memiliki kontrol penuh atas template itu sendiri tentu saja:
Metode ini harus digunakan dengan hati-hati, tentu saja, karena eval dapat mengeksekusi kode arbitrer. Menjalankan ini sebagai root cukup banyak dari pertanyaan. Kutipan dalam templat harus diloloskan, jika tidak maka akan dimakan oleh
eval
.Anda juga dapat menggunakan disini dokumen jika Anda lebih memilih
cat
untukecho
@plockc memprovokasi solusi yang menghindari masalah bash quote escape:
Sunting: Bagian yang dihapus tentang menjalankan ini sebagai root menggunakan ...
Sunting: Menambahkan komentar tentang bagaimana kutipan perlu diloloskan, menambahkan solusi plockc ke dalam campuran!
sumber
eval
edecho
/cat
perintah memprosesnya; cobaeval "echo \"'\$HOME'\""
.Saya punya solusi bash seperti mogsie tetapi dengan heredoc dan bukan herestring untuk memungkinkan Anda menghindari melarikan diri dari tanda kutip ganda
sumber
${param:?}
dan bersarang teks di sekitar parameter opsional. Contoh: tidak${DELAY:+<delay>$DELAY</delay>}
berkembang menjadi apa pun ketika DELAY tidak ditentukan dan <delay> 17 </delay> saat DELAY = 17._EOF_$$
.$trailing_newline
, atau gunakan$NL5
dan pastikan itu diperluas sebagai 5 baris baru.template.txt
akan berfungsi untuk menjaga jalur baru.eval
, jikatemplate.txt
berisiEOF
pada baris sendiri, itu akan mengakhiri prematur di sini-doc dan dengan demikian melanggar perintah. (Ujung topi ke @ xebeche).Edit 6 Jan 2017
Saya perlu menyimpan tanda kutip ganda dalam file konfigurasi saya sehingga lolos tanda kutip ganda dengan sed membantu:
Saya tidak bisa berpikir untuk tetap mengikuti garis baru, tetapi garis kosong di antaranya tetap dipertahankan.
Meskipun ini adalah topik lama, IMO saya menemukan solusi yang lebih elegan di sini: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/
Semua kredit untuk Grégory Pakosz .
sumber
eval "echo \"$(sed 's/\"/\\"/g' $1)\""
$variables
).Alih-alih menciptakan kembali roda, lanjutkan dengan envsubst Dapat digunakan di hampir semua skenario, misalnya membangun file konfigurasi dari variabel lingkungan dalam wadah buruh pelabuhan.
Jika di mac pastikan Anda memiliki homebrew kemudian tautkan dari gettext:
./template.cfg
./.env:
./configure.sh
Sekarang gunakan saja:
sumber
envsubst
benar - benar berfungsi.envsubst
tidak bekerja pada MacOS, Anda akan perlu untuk menginstalnya menggunakan homebrew:brew install gettext
.Versi lebih lama dari jawaban yang diterima:
Ini memperluas semua instance
$VAR
atau${VAR}
ke nilai lingkungannya (atau, jika tidak terdefinisi, string kosong).Itu benar lolos backslash, dan menerima $ backslash-melarikan diri untuk menghambat substitusi (tidak seperti envsubst, yang, ternyata, tidak melakukan ini ).
Jadi, jika lingkungan Anda adalah:
dan templat Anda adalah:
hasilnya adalah:
Jika Anda hanya ingin lepas dari garis miring terbalik sebelum $ (Anda dapat menulis "C: \ Windows \ System32" dalam templat yang tidak berubah), gunakan versi yang sedikit dimodifikasi ini:
sumber
Saya akan melakukannya dengan cara ini, mungkin kurang efisien, tetapi lebih mudah dibaca / dikelola.
sumber
sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
Jika Anda ingin menggunakan templat Jinja2 , lihat proyek ini: j2cli .
Ini mendukung:
sumber
Mengambil jawaban dari ZyX menggunakan bash murni tetapi dengan pencocokan regex gaya baru dan substitusi parameter tidak langsung menjadi:
sumber
Jika menggunakan Perl adalah opsi dan Anda puas dengan mendasarkan ekspansi hanya pada variabel lingkungan (sebagai lawan dari semua variabel shell ), pertimbangkan jawaban kuat Stuart P. Bentley .
Jawaban ini bertujuan untuk memberikan solusi bash-only yang - meskipun digunakan
eval
- harus aman digunakan .The tujuan adalah:
${name}
dan$name
referensi variabel.$(...)
dan sintaks yang lama`...`
)$((...))
dan sintaksis lama$[...]
).\
(\${name}
)."
dan\
contoh.Fungsi
expandVars()
:Contoh:
${HOME:0:10}
, selama tidak mengandung perintah tertanam atau penggantian aritmatika, seperti${HOME:0:$(echo 10)}
$(
dan`
contoh melarikan diri secara buta).${HOME
(hilang penutupan}
) BREAK fungsi.\$name
mencegah ekspansi.\
tidak diikuti oleh$
dipertahankan seperti apa adanya.\
instance yang berdekatan , Anda harus menggandakannya ; misalnya:\\
->\
- sama dengan adil\
\\\\
->\\
0x1
,0x2
,0x3
.eval
.Jika Anda mencari solusi yang lebih ketat yang hanya mendukung
${name}
ekspansi - yaitu, dengan kurung kurawal wajib , abaikan$name
referensi - lihat jawaban saya ini.Ini adalah versi perbaikan dari solusi bash-only,
eval
-gratis dari jawaban yang diterima :Perbaikannya adalah:
${name}
dan$name
referensi variabel.\
-menghapus referensi variabel yang tidak boleh diperluas.eval
solusi berbasis di atas,sumber
Inilah solusi bash murni lainnya:
$ cat code
$ cat template
(dengan mengikuti baris baru dan tanda kutip ganda)keluaran
sumber
Berikut ini solusi lain: menghasilkan skrip bash dengan semua variabel dan konten file templat, skrip tersebut akan terlihat seperti ini:
Jika kita memasukkan skrip ini ke bash, itu akan menghasilkan output yang diinginkan:
Inilah cara membuat skrip itu dan memasukkan skrip itu ke bash:
Diskusi
cat
perintah dengan HEREDOCJika Anda ingin mengarahkan output ini ke file, ganti baris terakhir dengan:
sumber
Halaman ini menjelaskan jawaban dengan awk
sumber
Kasing yang sempurna untuk shtpl . (proyek saya, jadi tidak banyak digunakan dan kurang dalam dokumentasi. Tapi di sini adalah solusi yang ditawarkan. Semoga Anda ingin mengujinya.)
Eksekusi saja:
Hasilnya adalah:
Selamat bersenang-senang.
sumber
Ini adalah fungsi bash murni yang dapat disesuaikan dengan keinginan Anda, digunakan dalam produksi dan tidak boleh merusak input apa pun. Jika rusak - beri tahu saya.
sumber
Anda juga dapat menggunakan bashible (yang secara internal menggunakan pendekatan evaluasi yang dijelaskan di atas / di bawah).
Ada contoh, cara membuat HTML dari banyak bagian:
https://github.com/mig1984/bashible/tree/master/examples/templates
sumber
Inilah fungsi bash yang mempertahankan spasi putih:
sumber
Berikut ini
perl
skrip yang dimodifikasi berdasarkan pada beberapa jawaban lain:Fitur (berdasarkan kebutuhan saya, tetapi harus mudah dimodifikasi):
sumber
Lihatlah skrip python substitusi variabel sederhana di sini: https://github.com/jeckep/vsubst
Sangat mudah digunakan:
sumber
Kontribusi saya yang sederhana terhadap pertanyaan yang luar biasa ini.
Ini pada dasarnya bekerja dengan menggunakan subkulit untuk melakukan penggantian envar kecuali bahwa ia tidak menggunakan eval dan ia lolos dari kutip tunggal dan ganda secara eksplisit. Ini menggabungkan ekspresi var menjadi satu baris tanpa spasi untuk tidak membingungkan
sh
dan kemudian meneruskan templateecho
, membiarkansh
menangani penggantian var. Ini mempertahankan baris baru, komentar dll ... dan Anda dapat melarikan diri\${like_this}
jika Anda tidak ingin var ditafsirkan.${missing_var}
hanya akan diganti dengan nilai kosong.Banyak jawaban lain di sini sangat bagus tetapi saya menginginkan sesuatu yang sangat sederhana dan tidak perlu menangani setiap kasus yang mungkin untuk kasus templating yang saya miliki saat ini.
Nikmati!
sumber
Untuk menindaklanjuti jawaban plockc pada halaman ini, berikut adalah versi yang cocok untuk Anda yang ingin menghindari bashism.
sumber
Tidak bisa lebih sederhana dari:
$ person = Bob ./render template.txt> rendered.txt
Lihat https://github.com/relaxdiego/renderest
sumber