Синтаксический анализ переменных из файла конфигурации в Bash

#bash

#bash #синтаксический анализ #переменные #awk

Вопрос:

Наличие следующего содержимого в файле:

 VARIABLE1="Value1"
VARIABLE2="Value2"
VARIABLE3="Value3"
  

Мне нужен скрипт, который выводит следующее:

 Content of VARIABLE1 is Value1
Content of VARIABLE2 is Value2
Content of VARIABLE3 is Value3
  

Есть идеи?

Ответ №1:

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

 . config_file
echo "Content of VARIABLE1 is $VARIABLE1"
echo "Content of VARIABLE2 is $VARIABLE2"
echo "Content of VARIABLE3 is $VARIABLE3"
  

Немного суше, но сложнее

 . config_file
for var in VARIABLE1 VARIABLE2 VARIABLE3; do
    echo "Content of $var is ${!var}"
done
  

Комментарии:

1. @samson во-первых, это позволяет вводить любой вредоносный код.

2. Зачем вам беспокоиться о вредоносном коде, вводимом из файла конфигурации? Полагаю, я мог бы представить такие случаи, но мне нужно было иметь возможность делать это из файла, который существует только на моем локальном компьютере, то есть списка комбинаций пользователя и пароля…

3. В этом ответе вам нужно жестко прописать имена переменных. С принятым ответом вы этого не делаете, и это то, что делает его намного лучше.

4. @samson, я бы беспокоился об этом, потому что способ, которым небольшие нарушения безопасности становятся крупными нарушениями безопасности, заключается в том, что злоумышленники находят эксплойты, которые они могут использовать для увеличения своего (часто изначально минимального) доступа. Файл конфигурации с небрежно назначенными разрешениями часто является именно такой возможностью.

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

Ответ №2:

awk -F= '{gsub(/"/,"",$2);print "Content of " $1 " is " $2}' <filename>

К вашему сведению, еще одно чистое решение bash

 IFS="="
while read -r name value
do
echo "Content of $name is ${value//"/}"
done < filename
  

Комментарии:

1. Вы также можете использовать IFS="=" read -r name value для обработки разделения ( -r это не имеет ничего общего с разделением, но рекомендуется, если у вас нет причин не использовать его).

Ответ №3:

Если вам это нужно…

Характеристики

  • Однострочные и встроенные комментарии;
  • Обрезка пробелов вокруг = (ie var = value не выйдет из строя);
  • Строковые значения в кавычках;
  • Понимание окончаний строк DOS;
  • Соблюдайте безопасность, избегая поиска вашего файла конфигурации.

Код

 shopt -s extglob
configfile="dos_or_unix" # set the actual path name of your (DOS or Unix) config file
tr -d 'r' < $configfile > $configfile.unix
while IFS='= ' read -r lhs rhs
do
    if [[ ! $lhs =~ ^ *# amp;amp; -n $lhs ]]; then
        rhs="${rhs%%#*}"    # Del in line right comments
        rhs="${rhs%%*( )}"   # Del trailing spaces
        rhs="${rhs%"*}"     # Del opening string quotes 
        rhs="${rhs#"*}"     # Del closing string quotes 
        declare $lhs="$rhs"
    fi
done < $configfile.unix
  

Комментарии

tr -d 'r' ... удаляет возврат каретки DOS.
! $lhs =~ ^ *# пропускает однострочные комментарии и -n $lhs пропускает пустые строки.
Для удаления конечных пробелов с ${rhs%%*( )} помощью требуется настройка расширенного глобулирования с shopt -s extglob помощью . (Помимо использования sed ), вы можете избежать этого с помощью более сложного:

 rhs="${rhs%"${rhs##*[^ ]}"}"  
  

Тестовый конфигурационный файл

 ## This is a comment 
var1=value1             # Right side comment 
var2 = value2           # Assignment with spaces 

## You can use blank lines 
var3= Unquoted String   # Outer spaces trimmed
var4= "My name is "     # Quote to avoid trimming 
var5= ""Bob""         
  

Тестовый код

 echo "Content of var1 is $var1"
echo "Content of var2 is $var2"
echo "Content of var3 is [$var3]"
echo "Content of var4   var5 is: [$var4$var5]"
  

Результаты

 Content of var1 is value1
Content of var2 is value2
Content of var3 is [Unquoted String]
Content of var4   var5 is: [My name is "Bob"]
  

Комментарии:

1. Разве rhs =»$ {rhs% » }» для закрывающих кавычек и rhs =»$ {rhs # » }» для открывающих кавычек?

2. и еще одна проблема: когда значение равно «aaaa #AAAAA», скрипт удаляет все в rhs из #

3. Я могу подтвердить, что этот скрипт завершается с ошибкой, если # в значении есть a.

Ответ №4:

Я делаю это таким образом

 . $PATH_TO_FILE
  

Комментарии:

1. аналогично тому, что сказал Дэйв Кеннеди, это позволяет вводить любой вредоносный код

2. Только если кто-то изменит исходный файл в «$ PATH_TO_FILE» на другой. Если кто-то может это сделать, значит, системный администратор неаккуратен.

Ответ №5:

 awk '{print "Content of "$1" is "$3}' FS='[="]'
  

Результат

Содержимое ПЕРЕМЕННОЙ 1 равно значению1
Содержимое ПЕРЕМЕННОЙ 2 равно значению2
Содержимое ПЕРЕМЕННОЙ 3 равно значению3

Ответ №6:

     # 
    #------------------------------------------------------------------------------
    # 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" 
            amp;amp; 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" amp;amp; 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 "nn"
        sleep 1; printf "33[2J";printf "33[0;0H" # and clear the screen
    }
    #eof func doParseConfFile
  

Ответ №7:

задан конфигурационный файл следующим образом :-

 [a]
b=C
d=E;rm t1
[b]
g=h
  

следующая однострочная строка проанализирует и сохранит значения :-

 CFG=path-to-file; for ini in `awk '/^[/' $CFG`;do unset ARHG;declare -A ARHG;while read A B;do ARHG[$A]=$B;echo "in section $ini, $A is equal to"  ${ARHG["$A"]};done < <(awk -F'=' '/[/ {x=0} x==1 amp;amp; $0~/=/ amp;amp; NF==2 {print $1, $2} $0==INI {x=1}' INI="$ini" $CFG);declare -p ARHG;echo;done;printf "end loopnn";declare -p ARHG
  

Теперь давайте разберем это

 CFG=path-to-file;
for ini in `awk '/^[/' $CFG` # finds the SECTIONS (aka "ini")
do 
  unset ARHG # resets ARHG 
  declare -A ARHG # declares an associative array
  while read A B
  do
    ARHG[$A]=$B
    echo "in section $ini, $A is equal to"  ${ARHG["$A"]}
  done < <(awk -F'=' '/[/ {x=0} x==1 amp;amp; $0~/=/ amp;amp; NF==2 {print $1, $2} $0==INI {x=1}' INI="$ini" $CFG)
  # the awk splits the file into sections, 
  # and returns pairs of values separated by "="
  declare -p ARHG # displays the current contents of ARHG
  echo
done
printf "end loopnn"
declare -p ARHG
  

Это позволяет нам сохранять значения, не используя eval или backtick.
Чтобы быть «действительно чистым», мы могли бы удалить [:space:] в начале и конце строки, игнорировать строки «^ #» и убрать пробелы вокруг знака «равно».

Комментарии:

1. конечно, для использования «declare -A» требуется последняя версия bash. Например, «GNU bash, версия 3.2.57 (1)-release (x86_64-apple-darwin14)» НЕ включает параметр «-A»…