Лучший способ прочитать конфигурационный файл в Bash

23

Каков наилучший способ прочитать конфигурационный файл в Bash?
Например, у вас есть скрипт, и вы не хотите заполнять всю конфигурацию вручную каждый раз, когда вы вызываете скрипт.

Изменить 1: я думаю, что я не дал понять, так что я хочу ... У меня есть файл конфигурации, который похож на

variable_name value  
variable_name value ...  

и я хочу это прочитать. Я знаю, я мог бы просто найти это для аргументов, которые я ищу или около того ... но, возможно, есть более разумный способ :)

IcyIcyIce
источник
2
Вам придется показать, какую конфигурацию вы имеете в виду. Приведите пример.
Муру
Смотрите также очень похожий вопрос по Unix & Linux StackExchange.
Майкл

Ответы:

38

Как сказал mbiber, sourceеще один файл. Например, ваш файл конфигурации (скажем some.config) будет:

var1=val1
var2=val2

И ваш скрипт может выглядеть так:

#! /bin/bash

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

. /path/to/some.config

echo "$var1" "$var2"

Многие файлы /etc/defaultобычно служат аналогичными конфигурационными файлами для других сценариев оболочки. Очень распространенный пример из постов здесь /etc/default/grub. Этот файл используется для установки параметров конфигурации для GRUB, поскольку grub-mkconfigэто сценарий оболочки, который его получает:

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

Если вам действительно нужно обработать конфигурацию формы:

var1 some value 1
var2 some value 2

Тогда вы можете сделать что-то вроде:

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

(Вы также можете сделать что-то подобное eval "$var=$value", но это более рискованно, чем поиск сценария. Вы можете непреднамеренно нарушить это легче, чем файл с источником.)

Мур
источник
Это отличный способ, я мог бы использовать замену sed вместо "="
IcyIcyIce
1
@IcyIcyIce Просто не надо. Почему вы не можете написать это с =самого начала?
Муру
1
@IcyIcyIce Вот как это должно быть. Вы можете использовать шелл-код в различных файлах /etc/default- и в основном для хорошего использования. Если ваш невежественный пользователь имеет доступ к конфигурации для чего-либо, работающего от имени пользователя root, это уже безнадежное дело.
Муру
1
@IcyIcyIce попросите ваших учителей уточнить, чего они хотят. Частью обучения разработке программного обеспечения является четкое ознакомление с требованиями.
Муру
1
@IcyIcyIce см. Обновление.
Муру
4

Очевидно, я не bash специалист, но концепция не должна отличаться на каком бы языке вы ни использовали:

Пример

В приведенном ниже примере вы можете использовать (очень) базовый сценарий, чтобы задать строку или напечатать строку, как указано в вашем конфигурационном файле:

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

затем

  • Чтобы установить строку в ваш конфигурационный файл:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Впоследствии, чтобы распечатать строку, как определено в вашем "configfile":

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

Конечно, в реальном прикладном скрипте вам нужно добавить много вещей, чтобы убедиться, что аргументы верны, решить, что делать, если ввод неправильный, файл настроек не существует и т. Д., Но:

Это основная идея

Якоб Влейм
источник
спасибо, я просто обновляю вопрос, который, я думаю, я не прояснил ... но в простых случаях это работало бы как очарование ofc
IcyIcyIce
4

Используйте sourceили .для загрузки в файл.

source /path/to/file

или

. /path/to/file

Также рекомендуется проверить, существует ли файл перед загрузкой, потому что вы не хотите продолжать запускать ваш скрипт, если файл конфигурации отсутствует.

mbiber
источник
0

Я использую этот ...

#!/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-файл анализируется с помощью sed, а затем оценивается как простые присвоения переменных

Первые значения ключа синтаксического анализа sed (поддерживает также = в окружении пробелов)

Второй sed удаляет пробелы вокруг знака = для правильного присвоения переменной

Может быть добавлено дальнейшее лечение седом

Весь другой не соответствующий тексту в файле conf будет удален (включая # или; комментарий и прочее)

Имейте в виду, что однострочные команды оболочки также могут быть оценены из этого файла конфигурации!

smARTin
источник
1
Бесполезное использованиеcat . Почему вы вызываете sedдважды спина к спине? Вы можете цепи sedкоманды типа так:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Форстер
Кроме того, эта sedкоманда сгенерирует пустой вывод для записей примера файла конфигурации в вопросе. -1
Дэвид Фёрстер
1
Другое возможное улучшение: используйте .перенаправление команд и процессов вместо временных переменных для хранения выходных данных . <(sed ... "$CFG_FILE")
Дэвид Фёрстер,
Конечно, мой пример использует ключ = значение, как файл конфигурации. Это лучшая практика, чем «ключевое значение». Используя ключ = значение, мой пример работает. Я допускаю, что ваша цепочка команд sed лучше, но исходная команда ожидает файл, который мы можем использовать:, eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")что намного лучше для понимания того, что происходит.
smARTin
Да, .ожидается , что подстановка файла и процесса будет расширена до файла. . <(echo echo foo)работает так же, как и ожидалось в Bash v4.3.11. В небольших примерах это, вероятно, не будет иметь значения. Я бы предпочел не передавать несколько килобайт через подстановку команд.
Дэвид Фёрстер
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
Йордан Георгиев
источник