Bash — перебор INI-разделов

#bash #for-loop #ini

#bash #для цикла #ini

Вопрос:

мой вопрос заключается в том, как прочитать ini-файл с несколькими разделами и передать значения раздела в переменные в цикле.

Вот мой файл batch.ini

 [section1]
val1='/home/test/'
val2='-i -200 -j 400%'

[section2]
val1='/home/test2/'
val2='-i -320 -j 333%'

[section3]
val1='/home/test3/'
val2='-i -223 -j 555%'
  

В моем bash-скрипте я хотел бы перебирать разделы по одному за раз и присваивать значения переменным в моем bash-скрипте. Мой псевдокод был бы таким:

 for sectionx = 1 to (number of sections)
do
   my_var1=sectionx(val1)
   my_var2=sectionx(val2)
   echo $my_var1 
   echo $my_var2 
done
  

Вывод:

 /home/test/
-i -200 -j 400%
/home/test2/
-i -320 -j 333%
/home/test3/
-i -223 -j 555%
  

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

1. Что вы пробовали? Где ваш существующий код? Для справки, когда я это делал, в итоге я использовал awk, и это была приятная, ужасная ошибка. В следующий раз я бы просто использовал perl.

2. @Tanktalus Существует, по крайней мере, псевдокод. Но то, что вы предложили, кажется правильным подходом.

3. Вопрос «что вы пробовали» больше касался sectionx(...) псевдовызова, чем вызывающего.

Ответ №1:

Если вам нужно прочитать .ini файлы в bash, я предлагаю вам использовать уже реализованное решение, например, анализатор Bash ini от rudimeier работает отлично.

Существуют также другие опции, такие как shini или анализатор от albfan.

Используя один от rudimeier, вы получите все значения в переменных bash с соответствующими именами.

Например, для вашего ini

 [section1]
val1='/home/test/'
val2='-i -200 -j 400%'

[section2]
val1='/home/test2/'
val2='-i -320 -j 333%'

[section3]
val1='/home/test3/'
val2='-i -223 -j 555%'
  

Вы получите следующие переменные bash:

 INI__ALL_SECTIONS='section1 section2 section3'
INI__ALL_VARS='INI__section1__val1 INI__section1__val2 INI__section2__val1 INI__section2__val2 INI__section3__val1 INI__section3__val2'
INI__NUMSECTIONS=3

INI__section1__val1=/home/test/
INI__section1__val2='-i -200 -j 400%'
INI__section2__val1=/home/test2/
INI__section2__val2='-i -320 -j 333%'
INI__section3__val1=/home/test3/
INI__section3__val2='-i -223 -j 555%'
  

С помощью этого вы можете выполнять итерации по разделам и переменным, например:

 for section in $INI__ALL_SECTIONS; do 
  echo "Variables in $section:"; 
  for var in `declare | grep "^INI__"$section"__"`; do 
    echo $var; 
  done; 
done;
  

Приведет к:

 Variables in section1:
INI__section1__val1=/home/test/
INI__section1__val2='-i -200 -j 400%'

Variables in section2:
INI__section2__val1=/home/test2/
INI__section2__val2='-i -320 -j 333%'

Variables in section3:
INI__section3__val1=/home/test3/
INI__section3__val2='-i -223 -j 555%'
  

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

1. Спасибо за это предложение. На самом деле я уже пробовал это, и это сработало для чтения моего файла .ini в набор переменных, однако я не смог увидеть способ программного обращения к переменным в цикле for: for ((i=1;ini_sec<=${INI__NUMSECTIONS};i )); do echo "section1 var1 = ${INI__section1__var1}" done

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

3. @ThatDude называть это «ответом только по ссылке» немного унизительно. Лично я рассматриваю это как ответ «не изобретайте велосипед». Как я упоминал, существует множество вариантов (намного больше, чем те, которые я связал). Решение работает нормально, как описано в моей правке. Я мог бы написать новый код, который выполняет именно то, что запрашивает OP, но зачем мне это? Кто-то другой уже сделал это, и это работает и удовлетворяет потребности OP.

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

5. Я решил это, добавив IFS=$'n' перед вторым for...loop . Теперь все работает нормально. Спасибо @brunorey

Ответ №2:

Я также столкнулся с проблемой обработки файлов .ini и придумал это решение.

Он использует один awk вызов, чтобы получить ответ, подходящий для создания ассоциативного массива, используя declare -A пары свойство / значение для данного раздела в файле .ini. Затем к этому можно запросить, чтобы получить значение, или повторить итерацию и использовать для создания и присвоения значений переменным.

Это достаточно общее, чтобы не было большой проблемы с адаптацией к различным сценариям.

Вот тестовый скрипт, демонстрирующий используемые инструкции awk и declare ;

 #!/bin/bash
#
# Parse a INI style properties file and extract property values for a given section
# 
# Author: Alan Carlyle
# License: CC0 (https://creativecommons.org/about/cclicenses/)
#
# Example Input: (example.properties)
#  [SEC1]
#  item1=value1
#  item2="value 2"
#
#  [Section 2]
#  property 1="Value 1 of 'Section 2'"
#  property 2='Single "quoted" value'
#
# Usage:  
# $ read_props example.properties "Section 2" property 2
# $ Single "quoted" value
#
# Section names and properties with spaces do not need to be quoted. 
# Values with spaces must be quoted. Values can use single or double quotes.
# The following characters [ = ] can not be used in names or values.
#
# If the property is not provided the the whole section is outputed.
#

propertiesFile=$1
section=$2
property=$3

# Extract the propetites for the section formated as for associtive array
sectionData="( "$(awk -F'=' -v s="$section" '/^[/{ gsub(/[[]]/, "", $1); f = ($1 == s); next } 
    NF amp;amp; f{ print "["$1"]="$2 }' $propertiesFile)" )"

# Create associtive array from extracted section data
declare  x -A "properties=$sectionData"

if [ -z "$property" ] 
then
  echo $sectionData
else
  echo ${properties[$property]}
fi