Чтение конфигурационного файла в BASH без использования «источника» - PullRequest
14 голосов
/ 14 декабря 2010

Я пытаюсь прочитать файл конфигурации, который отформатирован следующим образом:

USER = username
TARGET = arrows

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

  1. Чтение строк в массив
  2. Отфильтровать все строки, которые начинаются с #
  3. поиск имен переменных вмассив

После этого я потерялся.Любая помощь будет принята с благодарностью.Я пробовал что-то подобное безуспешно:

backup2.config>cat ~/1

grep '^[^#].*' | while read one two;do
    echo $two
done

Я извлек это из найденного поста на форуме, но не уверен, как его изменить в соответствии со своими потребностями, так как я новичок в сценариях оболочки.

http://www.linuxquestions.org/questions/programming-9/bash-shell-program-read-a-configuration-file-276852/


Можно ли автоматически присваивать переменную, циклически перебирая оба массива?

for (( i = 0 ; i < ${#VALUE[@]} ; i++ ))
do
    "${NAME[i]}"=VALUE[i]           
done
echo $USER

, чтобы при вызове $ USER получался«имя пользователя»?Приведенный выше код не работает, но я знаю, что решение похоже на это.

Ответы [ 4 ]

11 голосов
/ 14 декабря 2010

Следующий скрипт перебирает каждую строку в вашем входном файле ( vars в моем случае) и сопоставляет шаблон с =.Если знак равенства найден, он будет использовать Расширение параметра для анализа переменной name из значения .Затем он сохраняет каждую часть в своем собственном массиве, name и value соответственно.

#!/bin/bash

i=0
while read line; do
  if [[ "$line" =~ ^[^#]*= ]]; then
    name[i]=${line%% =*}
    value[i]=${line#*= }
    ((i++))
  fi
done < vars

echo "total array elements: ${#name[@]}"
echo "name[0]: ${name[0]}"
echo "value[0]: ${value[0]}"
echo "name[1]: ${name[1]}"
echo "value[1]: ${value[1]}"
echo "name array: ${name[@]}"
echo "value array: ${value[@]}"

Вход

$ cat vars
sdf
USER = username
TARGET = arrows
asdf
as23

Выход

$ ./varscript
total array elements: 2
name[0]: USER
value[0]: username
name[1]: TARGET
value[1]: arrows
name array: USER TARGET
value array: username arrows
5 голосов
/ 14 декабря 2010

Во-первых, USER - это переменная среды оболочки, поэтому может быть лучше, если вы используете что-то еще. Использование имен переменных в нижнем или смешанном регистре - это способ избежать конфликтов имен.

#!/bin/bash
configfile="/path/to/file"
shopt -s extglob
while IFS='= ' read lhs rhs
do
    if [[ $lhs != *( )#* ]]
    then
        # you can test for variables to accept or other conditions here
        declare $lhs=$rhs
    fi
done < "$configfile"

Это устанавливает переменные в вашем файле на значение, связанное с ним.

echo "Username: $USER, Target: $TARGET"

будет выводить

Имя пользователя: имя пользователя, Цель: стрелки

Другой способ сделать это с помощью ключей и значений - с помощью ассоциативного массива:

Добавьте эту строку перед циклом while:

declare -A settings

Удалите строку declare внутри петли while и замените ее на:

    settings[$lhs]=$rhs

Тогда:

# set keys
user=USER
target=TARGET
# access values
echo "Username: ${settings[$user]}, Target: ${settings[$target]}"

будет выводить

Имя пользователя: имя пользователя, Цель: стрелки

3 голосов
/ 06 июня 2013

У меня есть сценарий, который принимает только очень ограниченное количество настроек и обрабатывает их по одному, поэтому я адаптировал ответ SiegeX, чтобы внести в белый список нужные мне настройки и действовать в соответствии с ними.

Я также убрал требование к пробелам вокруг =, чтобы игнорировать все, что существует, используя функцию trim из другого ответа .

function trim()
{
    local var=$1;
    var="${var#"${var%%[![:space:]]*}"}";   # remove leading whitespace characters
    var="${var%"${var##*[![:space:]]}"}";   # remove trailing whitespace characters
    echo -n "$var";
}

while read line; do
    if [[ "$line" =~ ^[^#]*= ]]; then
        setting_name=$(trim "${line%%=*}");
        setting_value=$(trim "${line#*=}");

        case "$setting_name" in
            max_foos)
                prune_foos $setting_value;
            ;;
            max_bars)
                prune_bars $setting_value;
            ;;
            *)
                echo "Unrecognised setting: $setting_name";
            ;;
        esac;
    fi
done <"$config_file";
1 голос
/ 25 октября 2011

Спасибо SiegeX. Я думаю, что последующие обновления, которые вы упомянули, не отражаются в этом URL.

Мне пришлось отредактировать регулярное выражение, чтобы удалить кавычки, чтобы оно заработало. С кавычками возвращаемый массив пуст.

i=0
while read line; do
  if [[ "$line" =~ ^[^#]*= ]]; then
    name[i]=${line%% =*}
    value[i]=${line##*= }
    ((i++))
  fi
 done < vars

Еще лучшая версия.

i=0
while read line; do
if [[ "$line" =~ ^[^#]*= ]]; then
        name[i]=`echo $line | cut -d'=' -f 1`
            value[i]=`echo $line | cut -d'=' -f 2`
        ((i++))
fi
done < vars

Первая версия имеет проблемы, если в конфигурационном файле нет места до и после "=". Также, если значение отсутствует, я вижу, что имя и значение заполняются одинаково. Вторая версия не имеет ни одного из них. Кроме того, он удаляет нежелательные начальные и конечные пробелы.

Эта версия читает значения, которые могут иметь = внутри. Более ранняя версия разбивается при первом появлении =.

i=0
while read line; do
if [[ "$line" =~ ^[^#]*= ]]; then
        name[i]=`echo $line | cut -d'=' -f 1`
            value[i]=`echo $line | cut -d'=' -f 2-`
        ((i++))
fi
done < vars
...