Bir config dosyasını bash'de okumanın en iyi yolu


23

Bir config dosyasını bash'de okumanın en iyi yolu nedir?
Örneğin, bir komut dosyanız var ve komut dosyasını her çağırışınızda tüm yapılandırmayı el ile doldurmak istemiyorsunuz.

Düzenleme 1: Sanırım netleştirmedim, öyleyse: istediğim şey ... Benim gibi bir configfile'im var

variable_name value  
variable_name value ...  

ve bunu okumak istiyorum. Sadece aradığım argümanlar için elimden geldiğimi biliyorum ... ama belki daha akıllı bir yol var :)


2
Ne tür bir yapılandırma demek istediğinizi göstermek zorunda kalacaksınız. Bir örnek verin.
muru

Ayrıca Unix ve Linux StackExchange'te de benzer bir soruya bakın .
Michael,

Yanıtlar:


38

Mbiberin dediği gibi sourcebaşka bir dosya. Örneğin, config dosyanız (say some.config) şöyle olur:

var1=val1
var2=val2

Ve senaryonuz şuna benzeyebilir:

#! /bin/bash

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

. /path/to/some.config

echo "$var1" "$var2"

Çoğu dosya /etc/defaultgenellikle diğer kabuk komut dosyaları için benzer bir şekilde yapılandırma dosyaları görevi görür. Buradaki yayınlardan çok yaygın bir örnek /etc/default/grub. Bu dosya GRUB için yapılandırma seçeneklerini belirlemek için kullanılır, çünkü onu grub-mkconfigsağlayan bir kabuk betiğidir:

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

Form yapılandırmasını gerçekten işlemeniz gerekiyorsa:

var1 some value 1
var2 some value 2

O zaman şöyle bir şey yapabilirsin:

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

(Ayrıca böyle bir şey yapabilirdiniz eval "$var=$value", ancak bu bir senaryoyu yazmaktan daha riskli. Yanlışlıkla kaynaklı bir dosyadan daha kolay bozabilirsiniz.)


Bu harika bir yol, "=" için sed yerine boşluk
bırakabilirim

1
@ IcyIcyIce Sadece yapma. Neden =baştan yazmıyorsun ?
muru

1
@IcyIcyIce Öyle olması gerekiyordu. Kabuk kodunu çeşitli dosyalarda /etc/defaultkullanabilirsiniz - ve çoğunlukla iyi kullanmak için. İpucu sahibi olmayan kullanıcının kök olarak çalışan bir şeyin yapılandırmasına erişimi varsa, bu zaten kaybedilmiş bir nedendir.
muru

1
@IcyIcyIce öğretmenlerinin istediklerini netleştirmelerini sağlar. Yazılım geliştirmeyi öğrenmenin bir kısmı da gereksinimleri açıkça tanımaktır.
saat

1
@IcyIcyIce güncellemeye bakın.
muru

4

Açıkçası, buradaki bashuzman değilim , ama hangi dili kullandığınız kavramı farklı olmamalıdır:

Bir örnek

Aşağıdaki örnekte, bir dizgi ayarlamak veya config dosyanızda belirtildiği gibi bir dize yazdırmak için (çok) bir temel komut dosyası kullanabilirsiniz :

#!/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

Sonra

  • Config dosyasına dizge koymak için:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Daha sonra, "configfile" inizde tanımlandığı gibi dizeyi yazdırmak için:

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

Tabii ki, gerçek bir uygulamalı komut dosyasında, argümanların doğru olduğundan emin olmak için birçok şey eklemeniz gerekir, giriş yanlış olduğunda ne yapılacağına karar verin, ayarlar dosyası yok vb.

Bu temel fikir


teşekkürler, ben sadece ben bunu netleştirmek yapmadım sanırım soruyu güncelleştiriyorum ... ama basit durumlarda bu bir çekicilik gibi çalışacak
IcyIcyIce

4

Bir dosyayı yüklemek için sourceveya .düğmesini kullanın .

source /path/to/file

veya

. /path/to/file

Bir yapılandırma dosyası yoksa betiğinizi çalıştırmaya devam etmek istemediğiniz için, dosyayı yüklemeden önce var olup olmadığını kontrol etmeniz de önerilir.


0

Bunu kullanıyorum ...

#!/bin/bash

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

Conf dosyası sed ile ayrıştırılır ve sonra basit değişken atamaları olarak değerlendirilir.

İlk sed ayrıştırma anahtar değerleri (ayrıca destekler = boşluklarla çevrili)

İkinci sed, etrafındaki boşlukları kaldırır = geçerli değişken atama işareti

Daha fazla sed tedavi eklenebilir

Conf dosyasındaki eşleşmeyen diğer tüm metinler kaldırılacak (# veya; yorum ve diğer dahil)

Tek satırlı kabuk komutlarının da bu yapılandırma dosyasından değerlendirilebileceğini unutmayın!


1
Yararsız kullanımıcat . Neden sediki kez arka arkaya çağırıyorsunuz ? Aşağıdaki sedgibi komutları zincirleyebilirsiniz :sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster

Ayrıca, bu sedkomut söz konusu örnek yapılandırma dosyası girişleri için boş bir çıktı üretecektir. -1
David Foerster

1
Bir diğer olası gelişme: .Alt işlemin çıktısını almak için geçici değişkenler yerine komut ve işlem yönlendirmesini kullanın:. <(sed ... "$CFG_FILE")
David Foerster

Elbette benim örneğim, config = value gibi bir anahtar = kullanır. "Anahtar değer" den daha iyi bir uygulamadır. Key = value kullanarak örneğim çalışır. Sed komutları zincirlemeniz daha iyidir, itiraf ediyorum, ancak source komutu dosyayı kullanabilmemiz için bekliyor: eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")bu da neler olup bittiğini anlamanın daha iyi bir yolu.
smART

Evet, .bir dosya bekler ve işlem değişikliği bir dosyaya genişletilir. . <(echo echo foo)Bash v4.3.11'de beklendiği gibi çalışır. Küçük örneklerde muhtemelen önemi yoktur. Yine de komut yerine birden fazla kilobayt geçmemeyi tercih ederim.
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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.