Templating dengan Linux dalam Script Shell?


26

apa yang ingin saya selesaikan adalah:

1.) Memiliki file config sebagai templat, dengan variabel seperti $ version $ path (misalnya apache config)

2.) Memiliki skrip shell yang "mengisi" variabel template dan menulis file yang dihasilkan ke disk.

Apakah ini mungkin dengan skrip shell. Saya akan sangat berterima kasih jika Anda dapat menyebutkan beberapa perintah / alat saya bisa menyelesaikan ini atau beberapa tautan yang bagus.

Jawaban:


23

Ini sangat mungkin. Cara yang sangat sederhana untuk mengimplementasikan ini adalah agar file templat benar-benar menjadi skrip dan menggunakan variabel shell seperti

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
cat > /tmp/destfile <<-EOF
here is some config for version $version which should
also reference this path $path
EOF

Anda bahkan dapat membuat ini dapat dikonfigurasi pada baris perintah dengan menentukan version=$1dan path=$2, sehingga Anda dapat menjalankannya seperti bash script /foo/bar/baz 1.2.3. The -sebelum EOF menyebabkan spasi sebelum garis diabaikan, menggunakan plain <<EOFjika Anda tidak ingin perilaku itu.

Cara lain untuk melakukan ini adalah dengan menggunakan pencarian dan mengganti fungsi sed

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
sed -e "s/VERSION/$version/g" -e "s/PATH/$path/" /path/to/templatefile > /tmp/destfile

yang akan menggantikan setiap instance dari string VERSION dan PATH. Jika ada alasan lain, string-string itu ada di file template Anda mungkin membuat pencarian Anda dan ganti menjadi VERSION atau% VERSION% atau sesuatu yang cenderung dipicu secara tidak sengaja.


18

Tidak ada alat yang diperlukan selain /bin/sh. Diberikan file templat dari formulir

Version: ${version}
Path: ${path}

atau bahkan dengan kode shell campuran disertakan

Version: ${version}
Path: ${path}
Cost: ${cost}\$
$(i=1; for w in one two three four; do echo Param${i}: ${w}; i=$(expr $i + 1); done)

dan file konfigurasi seperti shell

version="1.2.3-r42"
path="/some/place/under/the/rainbow/where/files/dance/in/happiness"
cost="42"

itu adalah masalah sederhana untuk memperluas ini

Version: 1.2.3-r42
Path: /some/place/under/the/rainbow/where/files/dance/in/happiness
Cost: 42$
Param1: one
Param2: two
Param3: three
Param4: four

Memang, mengingat path ke file konfigurasi di variabel shell config_filedan path ke file template template_file, semua yang perlu Anda lakukan adalah:

. ${config_file}
template="$(cat ${template_file})"
eval "echo \"${template}\""

Ini mungkin lebih cantik daripada memiliki skrip shell lengkap sebagai file templat (solusi @ mtinberg).

Program expander template naif lengkap:

#!/bin/sh

PROG=$(basename $0)

usage()
{
    echo "${PROG} <template-file> [ <config-file> ]"
}

expand()
{
    local template="$(cat $1)"
    eval "echo \"${template}\""
}

case $# in
    1) expand "$1";;
    2) . "$2"; expand "$1";;
    *) usage; exit 0;;
esac

Ini akan menghasilkan ekspansi ke output standar; hanya mengarahkan keluaran standar ke file atau memodifikasi di atas dengan cara yang jelas untuk menghasilkan file keluaran yang diinginkan.

Peringatan: Perluasan file template tidak akan berfungsi jika file berisi tanda kutip ganda yang tidak terhapus ( "). Untuk alasan keamanan, kami mungkin harus menyertakan beberapa pemeriksaan kewarasan yang jelas atau, lebih baik lagi, melakukan transformasi shell escape jika file templat dihasilkan oleh entitas eksternal.


1
Sangat menyenangkan masih melihat orang-orang aktif menggunakan skrip shell untuk melakukan hal-hal menyenangkan seperti ini. Seorang teman saya menulis jam di skrip shell. github.com/tablespoon/fun/blob/master/cli-clock Waktu yang menyenangkan memang.
anak ayam

2
Ketika saya menemukan jawaban ini ketika ingin melakukan ini sendiri, saya menerapkan pendekatan yang cukup naif dan mempostingnya di Github: github.com/nealian/bash-unsafe-templates
Pyrocater

9

Cara termudah untuk melakukan ini hanya di Linux CLI adalah dengan menggunakan envsubstdan Variabel Lingkungan.

Contoh file template apache.tmpl:

<VirtualHost *:${PORT}>
    ServerName ${SERVER_NAME}
    ServerAlias ${SERVER_ALIAS}
    DocumentRoot "${DOCUMENT_ROOT}"
</VirtualHost>

Jalankan envsubstdan hasilkan output ke file baru my_apache_site.conf:

export PORT="443"
export SERVER_NAME="example.com"
export SERVER_ALIAS="www.example.com"
export DOCUMENT_ROOT="/var/www/html/"
envsubst < apache.tmpl > my_apache_site.conf

Keluaran:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot "/var/www/html/"
</VirtualHost>

2
Ini adalah bagian dari GNU gettext, dan karenanya tersedia di semua platform Unix utama (termasuk macOS X), serta Microsoft Windows.
tricasse

4

Anda mungkin harus melihat ke dalam sistem manajemen konfigurasi seperti Wayang atau Koki . Ini dapat dengan mudah melakukan apa yang Anda gambarkan di atas dan banyak lagi.


1
Terima kasih. Tentu saja, saya sudah menginstal dan menjalankan Chef. Tetapi itu menambah banyak overhead, ketika Anda harus menulis buku masak Anda sendiri. Saya tidak tahu bahasa pemrograman ruby ​​dan kesimpulan saya adalah. lebih mudah untuk melakukan ini dengan skrip shell untuk kasus-kasus yang lebih mudah (jika mungkin).
Markus

Sepertinya Wayang dan Koki sama-sama menggunakan ERB untuk templat, dan itu sangat mudah untuk memulai. Diberikan variabel name, string <%= name %>dalam templat akan diganti dengan namenilai. Bagaimana Anda mendefinisikan di nameluar template berbeda antara kedua sistem, jelas.
Mike Renfro

1
Ya templating (With Chef) itu sendiri sangat mudah. Tetapi menggunakan chef sebagai Kerangka (dan menulis buku masak) membutuhkan banyak waktu. Untuk mendapatkan data ke dalam templat, Anda perlu memahami di mana dan bagaimana Chef mengelola "penggabungan" sumber data dan banyak hal lainnya. Saya sudah mulai menulis buku masak saya sendiri, tetapi skrip shell dalam kasus khusus saya akan 100 kali lebih cepat ...
Markus

Mendapatkan infrastruktur untuk Chef atau Wayang bisa jadi menyebalkan atau Anda bisa mencoba mencari tahu bagaimana menjalankannya tanpa kepala yang merupakan petualangan yang menyenangkan. Kemungkinan berfungsi dengan baik dalam mode tarik atau dorong keluar dari kotak sehingga mungkin mendapatkan keseimbangan yang lebih baik dalam memahaminya dan membuat skrip sendiri. docs.ansible.com/template_module.html
chicks

4

Jika Anda menginginkan templat yang ringan dan nyata daripada kode shell yang menghasilkan file baru, pilihan yang biasa adalah sed& awkatau perl. Berikut ini satu tautan: http://savvyadmin.com/generate-text-from-templates-scripts-and-csv-data/

Saya, saya akan menggunakan bahasa nyata seperti perl, tcl, python, ruby ​​atau sesuatu yang lain di kelas itu. Sesuatu dibangun untuk skrip. Mereka semua memiliki alat templating yang bagus dan sederhana dan banyak contoh di google.


4

Saya menggunakan shtpl untuk itu. (proyek pribadi saya, yang berarti, itu tidak banyak digunakan. Tapi mungkin Anda ingin mengujinya pula)

Misalnya Anda ingin menghasilkan / etc / network / interfaces dari file csv, Anda dapat melakukannya seperti itu:

Konten file CSV (di sini test.csv):

eth0;10.1.0.10;255.255.0.0;10.1.0.1
eth1;192.168.0.10; 255.255.255.0;192.168.0.1

Templat (di sini interfaces.tpl):

#% IFS=';'
#% while read "Val1" "Val2" "Val3" "Val4"; do
auto $Val1 
iface $Val1 inet static
  address $Val2 
  netmask $Val3 
  gateway $Val4 

#% done < "$CSVFILE"

Perintah:

$ CSVFILE=test.csv sh -c "$( shtpl interfaces.tpl )"

Hasil:

auto eth0 
iface eth0 inet static
  address 10.1.0.10 
  netmask 255.255.0.0 
  gateway 10.1.0.1 

auto eth1 
iface eth1 inet static
  address 192.168.0.10 
  netmask  255.255.255.0 
  gateway 192.168.0.1

Nikmati!


1

Saya meningkatkan jawaban FooF sehingga pengguna tidak perlu menghapus tanda kutip ganda secara manual:

#!/bin/bash
template="$(cat $1)"
template=$(sed 's/\([^\\]\)"/\1\\"/g; s/^"/\\"/g' <<< "$template")
eval "echo \"${template}\""

1

Baru-baru ini saya menerbitkan skrip bash yang menyelesaikannya hanya dengan menggunakan sintaks template seperti-jinja. Ini disebut cookie . Ini demo:

demo cookie


Bagaimana ini menjawab pertanyaan?
RalfFriedl

1
@RalfFriedl Saya tidak yakin apa yang Anda maksud. Saya hanya membaca ulang pertanyaan itu dengan berpikir saya pasti melewatkan sesuatu, tetapi saya tidak melihatnya. Bahkan, bagaimana ini tidak menjawab setiap bagian dari pertanyaan yang diminta? Ini hampir seperti saya membuat kue dengan satu-satunya tujuan menjawab pertanyaan ini ... yang saya lakukan, meskipun saya mungkin telah mengatakannya sedikit berbeda di kepala saya pada saat itu. :)
Bryan Bugyi

Saya sedikit terlambat untuk menjadi mediator, tetapi mungkin Ralf hanya dengan murah hati mendorong Anda untuk menjelaskan bagaimana cookie menjawab pertanyaan, alih-alih mencoba menyiratkan bahwa Anda tidak tahu proyek Anda sendiri dengan cukup baik untuk menilai apakah itu bisa menyelesaikan masalah seseorang. .
abathur

0

Saya mungkin terlambat ke pesta ini. Namun, saya menemukan masalah yang sama dan saya memilih untuk membuat mesin template BASH saya sendiri dalam beberapa baris kode:

Katakanlah Anda memiliki ini file.template:

# My template
## Author
 - @NAME@ <@EMAIL@>

Dan rulesfile ini :

NAME=LEOPOLDO WINSTON
EMAIL=leothewinston\@leoserver.com

Anda menjalankan perintah ini:

templater rules < file.template

Anda mendapatkan ini:

# My template
## Author
 - LEOPOLDO WINSTON <leothewinston@leoserver.com>

Anda dapat menginstalnya dengan:

 bpkg install vicentebolea/bash-templater

Ini adalah situs proyek


0

Untuk memperluas jawaban hebat @ FooF (baris baru tidak memformat dalam komentar), menggunakan karakter kontrol heredoc +, Anda dapat mengizinkan karakter dan nama file yang berubah-ubah :

template() {
    # if [ "$#" -eq 0 ] ; then return; fi # or just error
    eval "cat <<$(printf '\x04\x04\x04');
$(cat $1)
"
}

Ini menerima karakter non-nol, dan hanya memotong lebih awal jika 3 ^Dbyte ditemui pada baris mereka sendiri (secara realistis tidak pernah). zsh bahkan mendukung terminator nol, jadi printf '\x00\x00\x00'akan bekerja. templatebahkan bekerja untuk nama file berbahaya seperti:

for num in `seq 10`; do
    template 'foo "$ .html' # works
done

Hati-hati templat shell dapat "memperluas" perintah sewenang-wenang, misalnya $(launch_nukes.sh --target $(curl -sL https://freegeoip.app/csv/ | cut -d, -f 9,10)). Dengan kekuatan besar ...

Sunting: jika Anda benar-benar tidak ingin file Anda meluncurkan nuklir pada Anda, hanya sudo -u nobody sh(atau pengguna aman lainnya) sebelumnya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.