it-swarm.com.ru

Чтение Java .properties файла из Bash

Я думаю об использовании sed для чтения файла .properties, но мне было интересно, есть ли более разумный способ сделать это из скрипта bash?

27
Alex N.

Решения, упомянутые выше, будут работать для основ. Я не думаю, что они охватывают многострочные значения. Вот программа awk, которая будет анализировать свойства Java из stdin и создавать переменные среды Shell для stdout:

BEGIN {
    FS="=";
    print "# BEGIN";
    n="";
    v="";
    c=0; # Not a line continuation.
}
/^\#/ { # The line is a comment.  Breaks line continuation.
    c=0;
    next;
}
/\\$/ && (c==0) && (NF>=2) { # Name value pair with a line continuation...
    e=index($0,"=");
    n=substr($0,1,e-1);
    v=substr($0,e+1,length($0) - e - 1);    # Trim off the backslash.
    c=1;                                    # Line continuation mode.
    next;
}
/^[^\\]+\\$/ && (c==1) { # Line continuation.  Accumulate the value.
    v= "" v substr($0,1,length($0)-1);
    next;
}
((c==1) || (NF>=2)) && !/^[^\\]+\\$/ { # End of line continuation, or a single line name/value pair
    if (c==0) {  # Single line name/value pair
        e=index($0,"=");
        n=substr($0,1,e-1);
        v=substr($0,e+1,length($0) - e);
    } else { # Line continuation mode - last line of the value.
        c=0; # Turn off line continuation mode.
        v= "" v $0;
    }
    # Make sure the name is a legal Shell variable name
    gsub(/[^A-Za-z0-9_]/,"_",n);
    # Remove newlines from the value.
    gsub(/[\n\r]/,"",v);
    print n "=\"" v "\"";
    n = "";
    v = "";
}
END {
    print "# END";
}

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

cat myproperties.properties | awk -f readproperties.awk > temp.sh
source temp.sh

Переменные будут иметь '_' вместо '.', Поэтому в оболочке свойство some.property будет иметь значение some_property.

Если у вас есть файлы свойств ANT, которые имеют интерполяцию свойств (например, $ {foo.bar} '), тогда я рекомендую использовать Groovy с AntBuilder.

Вот моя вики-страница на эту тему .

15
Joshua Davis

Вероятно, это будет самый простой способ: grep + cut

# Usage: get_property FILE KEY
function get_property
{
    grep "^$2=" "$1" | cut -d'=' -f2
}
26
Dmitry Trofimov

Я написал скрипт для решения проблемы и поместил его на свой github.

Смотрите свойства-парсер

9
Shawn

Один из вариантов - написать простую Java-программу, которая сделает это за вас, а затем запустить Java-программу в вашем скрипте. Это может показаться глупым, если вы просто читаете свойства из одного файла свойств. Однако это становится очень полезным, когда вы пытаетесь получить значение конфигурации из чего-то вроде Commons Configuration CompositeConfiguration, поддерживаемого файлами свойств. Какое-то время мы пошли по пути реализации того, что нам нужно в наших сценариях Shell, чтобы получить то же поведение, которое мы получали от CompositeConfiguration. Затем мы осознали и поняли, что должны просто позволить CompositeConfiguration сделать работу за нас! Я не ожидаю, что это будет популярный ответ, но, надеюсь, вы найдете его полезным.

4
Matt Hurne

В Perl:

while(<STDIN>) {
   ($prop,$val)=split(/[=: ]/, $_, 2);
   # and do stuff for each prop/val
}

Не проверено и должно быть более терпимым к пробелам, комментариям и т.д., Но вы поняли идею. Используете ли вы Perl (или другой язык) поверх sed, действительно зависит от того, что вы хотите сделать со свойствами после того, как вы проанализировали их из файла.

Обратите внимание, что (как отмечено в комментариях) файлы свойств Java могут иметь несколько форм разделителей (хотя я не видел на практике ничего, кроме двоеточий). Следовательно, разделение использует выбор символов для разделения. 

В конечном итоге, вам лучше использовать модуль Config :: Properties в Perl, который создан для решения этой конкретной проблемы.

1
Brian Agnew

Если вы хотите использовать sed для разбора файла -any- .properties, вы можете получить довольно сложное решение, так как формат допускает разрывы строк, строки без кавычек, юникод и т. Д .: http://en.wikipedia.org /wiki/.properties

Одним из возможных путей решения этой проблемы было бы использование самой Java для предварительной обработки файла .properties во что-то дружественное к bash, а затем его создание. Например.:

Файл .properties:

line_a : "ABC"
line_b = Line\
         With\ 
         Breaks!
line_c = I'm unquoted :(

будет превращен в:

line_a="ABC"
line_b=`echo -e "Line\nWith\nBreaks!"`
line_c="I'm unquoted :("

Конечно, это приведет к худшей производительности, но реализация будет проще/понятнее.

1
PaoloVictor

если вы хотите использовать «Shell», лучший инструмент для анализа файлов и надлежащего контроля над программированием - (g) awk. Используйте только простую подстановку.

0
ghostdog74

Иногда я просто искал файл свойств в скрипте bash. Это приведет к тому, что переменные среды будут установлены в скрипте с именами и содержимым из файла. Может быть, этого вам тоже достаточно. Если вам нужно выполнить «настоящий» анализ, конечно, это не тот путь.

0
Daniel Schneller

Хм, я просто столкнулся с той же проблемой сегодня. Это решение бедняка, по общему признанию, более простое, чем умное;)

decl=`Ruby -ne 'puts chomp.sub(/=(.*)/,%q{="\1";}).gsub(".","_")' my.properties`
eval $decl 

затем к свойству my.Java.prop можно получить доступ как $ my_Java_prop.

Это может быть сделано с помощью sed или чего-то еще, но я наконец-то выбрал Ruby для его «irb», который был удобен для экспериментов…. Он довольно ограничен (точки должны заменяться только перед «=», без обработки комментариев), но мог быть отправной точкой.

@Daniel, я пытался найти его, но Bash не нравились точки в именах переменных.

0
inger

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

dbUrlFile=$(grep database.url.file etc/zocalo.conf | sed -e "s/.*: //" -e "s/#.*//")

По сути, это grep для ключа и отфильтровывает вещи перед двоеточием и после любого хэша.

0
PanCrit

Я имел некоторый успех с

    PROPERTIES_FILE=project.properties
function source_property {
  local name=$1
  eval "$name=\"$(sed -n '/^'"$name"'=/,/^[A-Z]\+_*[A-Z]*=/p' $PROPERTIES_FILE|sed -e 's/^'"$name"'=//g' -e 's/"/\\"/g'|head -n -1)\""
}

    source_property 'SOME_PROPERTY'
0
aizen

Это решение, которое правильно анализирует кавычки и оканчивается на пробел, когда не даны кавычки. Это безопасно: никакой eval не используется.

Я использую этот код в моих .bashrc и .zshrc для импорта переменных из сценариев Shell:

# Usage: _getvar VARIABLE_NAME [sourcefile...]
# Echos the value that would be assigned to VARIABLE_NAME
_getvar() {
  local VAR="$1"
  shift
  awk -v Q="'" -v QQ='"' -v VAR="$VAR" '
    function loc(text) { return index($0, text) }
    function unquote(d) { $0 = substr($0, eq+2) d; print substr($0, 1, loc(d)-1) }
    { sub(/^[ \t]+/, ""); eq = loc("=") }
    substr($0, 1, eq-1) != VAR { next }  # assignment is not for VAR: skip
    loc("=" QQ) == eq { unquote(QQ); exit }
    loc("="  Q) == eq { unquote( Q); exit }
    { print substr($1, eq + 1); exit }
  ' "[email protected]"
}

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

Поскольку так трудно вызывать переменные оболочки и ссылаться на символы кавычек внутри awk, я определяю их как переменные awk в командной строке. Q - это символ одинарной кавычки (апостроф), QQ - двойная кавычка, а VAR - это первый аргумент, который мы сохранили ранее.

Для дальнейшего удобства есть две вспомогательные функции. Первый возвращает местоположение данного текста в текущей строке, а второй печатает содержимое между первыми двумя кавычками в строке, используя символ кавычки d (для «разделителя»). Для защиты от многострочных строк существует случайный d, соединенный с первым substr (см. «Предостережения» ниже).

Хотя я написал код для синтаксического разбора POSIX Shell, он, похоже, отличается от вашего формата только наличием пробела вокруг присвоения. Вы можете добавить эту функциональность в приведенный выше код, добавив sub(/[ \t]*=[ \t]*/, "="); перед sub(…) в строке 4 awk (примечание: строка 1 пуста).

Четвертая строка убирает начальные пробелы и сохраняет местоположение первого знака равенства. Убедитесь, что ваш awk поддерживает \t as tab, это не гарантируется в древних системах UNIX.

Строка substr сравнивает текст перед знаком равенства с VAR. Если это не совпадает, строка назначает другую переменную, поэтому мы пропускаем ее и переходим к следующей строке.

Теперь мы знаем, что получили запрошенное присвоение переменной, так что это просто вопрос распутывания кавычек. Мы делаем это путем поиска первого местоположения =" (строка 6) или =' (строка 7) или отсутствия кавычек (строка 8). Каждая из этих строк печатает назначенное значение.

Предостережения: если есть экранированный символ кавычки, мы вернем ему усеченное значение. Обнаружение этого немного нетривиально, и я решил не реализовывать его. Существует также проблема многострочных кавычек, которые усекаются при первом разрыве строки (это и есть цель "stray d", упомянутой выше). Большинство решений на этой странице страдают от этих проблем.

0
Adam Katz