Как получить значение из строки «ключ = значение» из файла? - PullRequest
0 голосов
/ 04 мая 2018

Дан файл с содержимым следующей формы:

// This is a comment
FOO = 1
BAR = 0
// Comments can be anywhere...
BAZ = 10 //...even here!

Ключи всегда будут привязаны к началу строки, но с любой стороны символа '=' может быть любое количество пробелов. Значение также может быть отслежено любым количеством пробелов.

РЕДАКТИРОВАТЬ: Значение и / или его завершающие пробелы могут также сопровождаться комментарием.

Как я могу получить значение ключа как однострочное, используя bash сценарии и / или awk или sed? Я хотел бы иметь возможность сделать что-то вроде:

MYVAL=$(<string manipulation to get value of "BAZ" from /tmp/foo.txt>)

чтобы прибыть в

>echo $MYVAL
10
>

Я довольно ужасен в скриптах bash; никогда не достаточно свободно владел набором инструментов для работы со строками, чтобы знать, как к этому приблизиться Самое дальнее, что я мог получить, было

> grep BAZ /tmp/foo.txt
BAZ = 10

и действительно не знал, что делать дальше.

Я искал вокруг SO, но не смог найти решение с той же предпосылкой (в частности, наличие переменного числа пробелов по обе стороны от '='), и решения для похожие вопросы не сработали в моей предпосылке.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Однострочное решение с sed:

MYVAR=$(sed -nE 's/^BAZ\s*=\s*(\S*)$/\1/p' inputfile)

Как отмечено в одном комментарии, эта команда sed не даст желаемого результата в следующем сценарии:

BAZ = 10 // some comment ending with 0

Здесь MYVAR будет назначено 0 вместо 10. Чтобы исправить эту проблему, регулярное выражение можно изменить на:

MYVAR=$(sed -nE 's/^BAZ\s*=\s*([^\s\/]*).*/\1/p' inputfile)

Теперь MYVAR - это 10 по мере необходимости. Разбивая регулярное выражение:

^BAZ\s*=\s*([^\s\/]*).*/\1
^                           Match beginning of line
 BAZ                        Match BAZ
    \s*=\s*                 Match equal sign surrounded by zero or more spaces
           ([^\s\/]*)       Capture in Group 1 any character that is not space or slash
                     .*     Match the rest of the text
                       /\1  Replace matched text with text in Group 1
0 голосов
/ 04 мая 2018

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

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Requires bash 4.0" >&2; exit 1;; esac

shopt -s extglob                     # make *([[:space:]]) mean "zero-or-more spaces"
declare -A array=( )

while read -r line; do
  line=${line%%*([[:space:]])"//"*}  # trim everything after the first "//" in the line
  [[ $line = *=* ]] || continue      # skip lines without an "=" after this is done
  key=${line%%*([[:space:]])=*}      # key is everything before the first "=" & whitespace
  value=${line#*=}                   # value is everything after the first "="
  value=${value##+([[:space:]])}     # remove leading spaces from value
  array[$key]=$value
done

# print result to stderr
declare -p array >&2

См. Это работает на https://ideone.com/UwYs3C,, имея для ввода данных в вопросе следующий результат:

declare -A array=([FOO]="1" [BAR]="0" [BAZ]="10" )

... таким образом, можно echo "Read value for foo as ${array[FOO]}" излучать Read value for foo as 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...