从bash中读取java .properties文件

时间:2009-11-05 18:04:24

标签: bash scripting properties

我正在考虑使用sed来读取.properties文件,但是想知道是否有更聪明的方法可以从bash脚本中执行此操作?

12 个答案:

答案 0 :(得分:26)

这可能是最简单的方法:grep + cut

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

答案 1 :(得分:15)

上述解决方案适用于基础知识。我不认为它们涵盖多行值。这是一个awk程序,它将从stdin解析Java属性并生成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将在shell中为some_property。

如果您有具有属性插值的ANT属性文件(例如'$ {foo.bar}'),那么我建议将Groovy与AntBuilder一起使用。

这是my wiki page on this very topic

答案 2 :(得分:9)

我编写了一个脚本来解决问题并将其放在我的github上。

请参阅properties-parser

答案 3 :(得分:4)

一种选择是编写一个简单的Java程序来为您完成 - 然后在脚本中运行Java程序。如果您只是从单个属性文件中读取属性,那可能看起来很愚蠢。但是,当您尝试从属性文件支持的Commons Configuration CompositeConfiguration获取配置值时,它变得非常有用。有一段时间,我们在shell脚本中实现了我们需要的路径,以获得我们从CompositeConfiguration获得的相同行为。然后我们明智地意识到我们应该让CompositeConfiguration为我们做好工作!我不认为这是一个受欢迎的答案,但希望你发现它很有用。

答案 4 :(得分:1)

Perl:

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

未经测试,应该更能容忍前导/尾随空格,评论等,但您明白了。是否使用Perl(或其他语言)而不是sed实际上取决于您在将属性解析出文件后要对属性执行的操作。

请注意(在评论中突出显示)Java属性文件可以有multiple forms of delimiters(虽然我没有看到除了冒号之外的任何实践)。因此,拆分使用选择的字符进行拆分。

最终,您可能最好使用Perl中的Config::Properties模块,它是为解决此特定问题而构建的。

答案 5 :(得分:1)

如果你想使用sed来解析-any- .properties文件,你可能会得到一个非常复杂的解决方案,因为格式允许换行符,不带引号的字符串,unicode等:http://en.wikipedia.org/wiki/.properties

一种可能的解决方法是使用java本身将.properties文件预处理为bash-friendly,然后获取它。 E.g:

.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 :("

当然,这会产生更糟糕的表现,但实施会更简单/更清晰。

答案 6 :(得分:0)

我有一些shell scripts需要查找一些.properties并将它们用作我没写过的程序的参数。脚本的核心是这样的一行:

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

实际上,这是密钥的grep,并在冒号之前和任何哈希之后过滤掉东西。

答案 7 :(得分:0)

如果你想使用“shell”,解析文件和正确编程控制的最佳工具是(g)awk。使用sed只是简单的替换。

答案 8 :(得分:0)

我有时只是将属性文件发送到bash脚本中。这将导致在脚本中使用文件中的名称和内容设置环境变量。也许这对你来说已经足够了。如果你必须做一些“真正的”解析,当然这不是一种方法。

答案 9 :(得分:0)

嗯,我今天遇到了同样的问题。这是穷人的解决方案,无可否认比聪明更直接;)

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

然后,属性'my.java.prop'可以作为$ my_java_prop访问。

这可以用sed或者其他什么来完成,但我最终选择了红宝石用于它的'irb',这对于实验很方便。 这是非常有限的(点应该只在'='之前替换,没有评论处理),但可能是一个起点。

@Daniel,我试图找到它,但是Bash不喜欢变量名中的点。

答案 10 :(得分:0)

我已经取得了一些成功

    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'

答案 11 :(得分:0)

这是一种解决方案,可以正确地解析引号,并在不提供引号时以空格终止。是安全的:不使用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 }
  ' "$@"
}

这将保存所需的变量名,然后移动参数数组,以便其余部分可以作为文件传递到awk

由于很难调用shell变量并引用awk中的引号字符,因此我在命令行上将它们定义为awk变量。 Q是单引号(撇号)字符,QQ是双引号,而VAR是我们之前保存的第一个参数。

为进一步方便起见,有两个帮助程序功能。第一个返回给定文本在当前行中的位置,第二个使用引号字符d(对于“定界符”)在行的前两个引号之间打印内容。有一个流浪d与第一个substr串联在一起,以防止出现多行字符串(请参阅下面的“注意事项”)。

虽然我编写了POSIX Shell语法解析的代码,但看起来仅与您的格式有所不同,即作业周围是否有空格。您可以通过在awk的第4行的sub(/[ \t]*=[ \t]*/, "=");之前添加sub(…)来将该功能添加到上述代码中(注意:第1行为空白)。

第四行去除前导空白并保存第一个等号的位置。请验证您的awk是否支持\t作为标签,在古老的UNIX系统上不能保证。

substr行将等号之前的文本与VAR进行比较。如果不匹配,则该行正在分配其他变量,因此我们将其跳过并移至下一行。

现在,我们知道我们已经拥有所请求的变量赋值,因此只需解开引号即可。为此,我们搜索="(第6行)或='(第7行)或不加引号(第8行)的第一个位置。这些行中的每一行都会打印分配的值。

注意事项:如果有转义的引号字符,我们将返回一个被截断的值。检测到这一点并不容易,我决定不实施它。还有一个多行引号的问题,该引号在第一个换行符处被截断(这是上面提到的“ stray d”的目的)。此页面上的大多数解决方案都遇到这些问题。