Cara terbaik untuk membaca file konfigurasi di bash

23

Apa cara terbaik untuk membaca file konfigurasi di bash?
Misalnya, Anda memiliki skrip dan tidak mau mengisi semua konfigurasi secara manual setiap kali Anda memanggil skrip.

Sunting 1: Saya pikir saya tidak memperjelas, jadi: yang saya inginkan adalah ... Saya memiliki konfigurasi yang seperti

variable_name value  
variable_name value ...  

dan saya ingin membacanya. Saya tahu saya hanya bisa menerima argumen yang saya cari atau lebih ... tapi mungkin ada cara yang lebih cerdas :)

IcyIcyIce
sumber
2
Anda harus menunjukkan konfigurasi apa yang Anda maksud. Berikan contoh.
muru
Lihat juga pertanyaan yang sangat mirip pada Unix & Linux StackExchange.
Michael

Jawaban:

38

Seperti kata mbiber, sourcefile lain. Misalnya, file konfigurasi Anda (misalnya some.config) adalah:

var1=val1
var2=val2

Dan skrip Anda dapat terlihat seperti:

#! /bin/bash

# Optionally, set default values
# var1="default value for var1"
# var1="default value for var2"

. /path/to/some.config

echo "$var1" "$var2"

Banyak file dalam /etc/defaultbiasanya berfungsi sebagai file konfigurasi untuk skrip shell lain dengan cara yang sama. Contoh yang sangat umum dari posting di sini adalah /etc/default/grub. File ini digunakan untuk mengatur opsi konfigurasi untuk GRUB, karena grub-mkconfigskrip shell yang sumbernya:

sysconfdir="/etc"
#…
if test -f ${sysconfdir}/default/grub ; then
  . ${sysconfdir}/default/grub
fi

Jika Anda benar-benar harus memproses konfigurasi formulir:

var1 some value 1
var2 some value 2

Maka Anda dapat melakukan sesuatu seperti:

while read var value
do
    export "$var"="$value"
done < /path/to/some.config

(Anda juga bisa melakukan sesuatu seperti eval "$var=$value", tapi itu lebih berisiko daripada sumber skrip. Anda secara tidak sengaja dapat memecahkan itu lebih mudah daripada file yang bersumber.)

muru
sumber
Itu cara yang hebat, saya bisa menggunakan spasi pengganti pengganti untuk "="
IcyIcyIce
1
@IcyIcyIce Tapi jangan. Mengapa Anda tidak bisa menulisnya =sejak awal?
muru
1
@IcyIcyIce Begitulah seharusnya. Anda dapat menggunakan kode shell di berbagai file di /etc/default- dan sebagian besar digunakan dengan baik. Jika pengguna yang tidak mengerti Anda memiliki akses ke konfigurasi untuk sesuatu yang berjalan sebagai root, itu sudah menjadi penyebab hilang.
muru
1
@IcyIcyIce minta guru-guru Anda menjelaskan apa yang mereka inginkan. Bagian dari pembelajaran untuk mengembangkan perangkat lunak adalah untuk mengetahui persyaratan dengan jelas.
muru
1
@IcyIcyIce lihat pembaruan.
muru
4

Jelas, saya bukan bashspesialis di sini, tetapi konsepnya tidak boleh berbeda dalam bahasa apa pun yang Anda gunakan:

Sebuah contoh

Dalam contoh di bawah ini, Anda dapat menggunakan skrip dasar (sangat) untuk mengatur string, atau mencetak string, seperti yang diatur dalam file konfigurasi Anda:

#!/bin/bash

# argument to set a new string or print the set string
arg=$1
# possible string as second argument
string=$2
# path to your config file
configfile="$HOME/stringfile"

# if the argument is: "set", write the string (second argument) to a file
if [ "$arg" == "set" ]
then
echo "$string" > $configfile 
# if the argunment is "print": print out the set string, as defined in your file
elif [ "$arg" == "print" ]
then 
echo "$( cat $configfile )"
fi

Kemudian

  • Untuk mengatur string ke file konfigurasi Anda:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Selanjutnya, untuk mencetak string, seperti yang didefinisikan dalam "configfile" Anda:

    $ '/home/jacob/Bureaublad/test.sh' print
    Een aap op een fiets, hoe vind je zoiets?

Tentu saja, dalam skrip yang diterapkan nyata, Anda perlu menambahkan banyak hal untuk memastikan argumennya benar, memutuskan apa yang harus dilakukan ketika input salah, file pengaturan tidak ada dll, tetapi:

Ini adalah ide dasar

Yakub Vlijm
sumber
terima kasih, saya baru saja memperbarui pertanyaan saya pikir saya tidak membuatnya jelas ... tetapi dalam kasus-kasus sederhana ini akan berfungsi seperti pesona ofc
IcyIcyIce
4

Gunakan sourceatau .untuk memuat dalam file.

source /path/to/file

atau

. /path/to/file

Anda juga disarankan untuk memeriksa apakah file tersebut ada sebelum memuatnya karena Anda tidak ingin melanjutkan menjalankan skrip Anda jika file konfigurasi tidak ada.

mbiber
sumber
0

Saya menggunakan yang ini ...

#!/bin/bash

CFG_FILE=/etc/test.conf
CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval "$CFG_CONTENT"

File conf diuraikan dengan sed dan kemudian dievaluasi sebagai tugas variabel sederhana

Nilai kunci parsing sed sed pertama (mendukung juga = dikelilingi dengan spasi)

Sed kedua menghapus spasi di sekitar = tanda untuk penetapan variabel yang valid

Perawatan sed yang lebih lanjut dapat ditambahkan

Semua teks lain yang tidak cocok dengan file conf akan dihapus (termasuk # atau; komentar dan lainnya)

Ketahuilah bahwa perintah shell baris tunggal juga dapat dievaluasi dari file konfigurasi ini!

smARTin
sumber
1
Penggunaan tidak bergunacat . Mengapa Anda memohon seddua kali back-to-back? Anda dapat mengaitkan sedperintah seperti ini:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster
Juga, sedperintah ini akan menghasilkan output kosong untuk entri file konfigurasi sampel dalam pertanyaan. -1
David Foerster
1
Peningkatan lain yang mungkin: gunakan .perintah dan proses pengalihan bukan variabel sementara untuk menahan output dari sub-proses:. <(sed ... "$CFG_FILE")
David Foerster
Tentu saja contoh saya menggunakan key = value seperti file config. Ini adalah praktik yang lebih baik daripada "nilai kunci". Menggunakan kunci = nilai contoh saya berfungsi. Chaining Anda tentang perintah sed lebih baik, saya akui, tetapi perintah sumber mengharapkan file sehingga kita dapat menggunakan:, eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")yang merupakan cara yang lebih baik untuk memahami apa yang sedang terjadi.
smARTin
Ya, .mengharapkan file dan proses substitusi diperluas ke file. . <(echo echo foo)berfungsi seperti yang diharapkan dalam Bash v4.3.11. Dalam contoh kecil mungkin tidak masalah. Saya lebih suka tidak melewati beberapa kilobyte melalui substitusi perintah.
David Foerster
0
#------------------------------------------------------------------------------
# parse the ini like $0.$host_name.cnf and set the variables
# cleans the unneeded during after run-time stuff. Note the MainSection
# courtesy of : http://mark.aufflick.com/blog/2007/11/08/parsing-ini-files-with-sed
#------------------------------------------------------------------------------
doParseConfFile(){
    # set a default cnfiguration file
    cnf_file="$run_unit_bash_dir/$run_unit.cnf"

    # however if there is a host dependant cnf file override it
    test -f "$run_unit_bash_dir/$run_unit.$host_name.cnf" \
    && cnf_file="$run_unit_bash_dir/$run_unit.$host_name.cnf"

    # yet finally override if passed as argument to this function
    # if the the ini file is not passed define the default host independant ini file
    test -z "$1" || cnf_file=$1;shift 1;


    test -z "$2" || ini_section=$2;shift 1;
    doLog "DEBUG read configuration file : $cnf_file"
    doLog "INFO read [$ini_section] section from config file"

    # debug echo "@doParseConfFile cnf_file:: $cnf_file"
    # coud be later on parametrized ...
    test -z "$ini_section" && ini_section='MAIN_SETTINGS'

    doLog "DEBUG reading: the following configuration file"
    doLog "DEBUG ""$cnf_file"
    ( set -o posix ; set ) | sort >"$tmp_dir/vars.before"

    eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
        -e 's/#.*$//' \
        -e 's/[[:space:]]*$//' \
        -e 's/^[[:space:]]*//' \
        -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
        < $cnf_file \
        | sed -n -e "/^\[$ini_section\]/,/^\s*\[/{/^[^#].*\=.*/p;}"`

    ( set -o posix ; set ) | sort >"$tmp_dir/vars.after"

    doLog "INFO added the following vars from section: [$ini_section]"
    cmd="$(comm -3 $tmp_dir/vars.before $tmp_dir/vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
    echo -e "$cmd"
    echo -e "$cmd" >> $log_file
    echo -e "\n\n"
    sleep 1; printf "\033[2J";printf "\033[0;0H" # and clear the screen
}
#eof func doParseConfFile
Yordan Georgiev
sumber