Прочитайте конфигурационный файл в BASH без использования "source"

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

USER = username
TARGET = arrows

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

  • Чтение строк в массив
  • Отфильтровать все строки, начинающиеся С#
  • искать имена переменных в массиве

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

backup2.config>cat ~/1

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

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

http://www.linuxquestions.org/info/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 выдавал "имя пользователя"? Вышеприведенный код не работает, но я знаю, что решение похоже на это.

Ответы

Ответ 1

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

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

Ответ 2

Во-первых, 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"

Это устанавливает в файле vars значение, связанное с ним.

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

выводит

Username: username, Target: arrows

Ответ 3

У меня есть script, который принимает только очень ограниченное количество настроек и обрабатывает их по одному, поэтому я адаптировал 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";

Ответ 4

Спасибо 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