web-dev-qa-db-fra.com

Lecture du fichier .properties Java à partir de bash

Je songe à utiliser sed pour lire le fichier .properties, mais je me demandais s’il existait un moyen plus intelligent de le faire à partir du script bash?

27
Alex N.

Les solutions mentionnées ci-dessus fonctionneront pour les bases. Je ne pense pas qu'ils couvrent des valeurs multi-lignes cependant. Voici un programme awk qui analysera les propriétés Java de stdin et produira des variables d'environnement Shell dans 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";
}

Comme vous pouvez le constater, les valeurs multilignes rendent les choses plus complexes. Pour voir les valeurs des propriétés dans Shell, il suffit de source dans la sortie:

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

Les variables auront '_' à la place de '.', Ainsi la propriété some.property sera some_property dans Shell.

Si vous avez des fichiers de propriétés ANT avec une interpolation de propriété (par exemple, '$ {foo.bar}'), je vous recommande d'utiliser Groovy avec AntBuilder.

Voici ma page wiki sur ce sujet même .

15
Joshua Davis

Ce serait probablement le moyen le plus simple: grep + cut

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

J'ai écrit un script pour résoudre le problème et le mettre sur mon github.

Voir propriétés-parser

9
Shawn

Une option consiste à écrire un programme Java simple pour le faire à votre place, puis exécutez le programme Java dans votre script. Cela peut paraître idiot si vous ne faites que lire les propriétés d’un seul fichier de propriétés. Cependant, cela devient très utile lorsque vous essayez d'obtenir une valeur de configuration à partir de quelque chose comme une configuration commune CompositeConfiguration sauvegardée par des fichiers de propriétés. Pendant un certain temps, nous avons implémenté ce que nous avions besoin dans nos scripts Shell pour obtenir le même comportement que nous obtenions de CompositeConfiguration. Nous nous sommes ensuite rendus compte que nous devrions laisser CompositeConfiguration faire le travail pour nous! Je ne m'attends pas à ce que cette réponse soit populaire, mais j'espère que vous la trouverez utile.

4
Matt Hurne

En Perl:

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

Non testé, et devrait être plus tolérant vis-à-vis des espaces de début/fin, des commentaires, etc., mais vous voyez l'idée. Que vous utilisiez Perl (ou une autre langue) sur sed dépend vraiment de ce que vous voulez faire avec les propriétés une fois que vous les avez analysées hors du fichier.

Notez que (comme indiqué dans les commentaires), les fichiers de propriétés Java peuvent avoir plusieurs formes de délimiteurs (bien que je n’aie jamais rien vu d’utile utilisé autre que le deux-points). Par conséquent, la scission utilise un choix de caractères à scinder. 

En fin de compte , vous feriez peut-être mieux d'utiliser le module Config :: Properties de Perl, conçu pour résoudre ce problème spécifique.

1
Brian Agnew

Si vous voulez utiliser sed pour analyser le fichier -any- .properties, vous pouvez vous retrouver avec une solution assez complexe, car le format autorise les sauts de ligne, les chaînes non mises entre guillemets, unicode, etc.: http://fr.wikipedia.org /wiki/.properties

Une solution de contournement consiste à utiliser Java lui-même pour prétraiter le fichier .properties dans un format compatible avec bash, puis l’alimenter. Par exemple.:

Fichier .properties:

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

serait transformé en:

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

Bien sûr, cela donnerait de moins bonnes performances, mais la mise en œuvre serait plus simple/plus claire.

1
PaoloVictor

si vous souhaitez utiliser "Shell", le meilleur outil pour analyser les fichiers et disposer du contrôle de programmation approprié est (g) awk. Utilisez sed uniquement la substitution simple.

0
ghostdog74

Je viens parfois de chercher le fichier de propriétés dans le script bash. Cela conduira à la définition de variables d'environnement dans le script avec les noms et le contenu du fichier. Peut-être que cela vous suffit aussi. Si vous devez faire de "vraies" analyses, ce n'est pas la voie à suivre, bien sûr.

0
Daniel Schneller

Hmm, je viens de rencontrer le même problème aujourd'hui. C'est la solution du pauvre, certes plus simple qu'astucieuse;)

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

ensuite, une propriété 'my.Java.prop' est accessible en tant que $ my_Java_prop.

Cela peut être fait avec sed ou autre chose, mais j'ai finalement choisi Ruby pour son 'irb' qui était pratique pour expérimenter. mais pourrait être un point de départ.

@ Daniel, j'ai essayé de le trouver, mais Bash n'aimait pas les points dans les noms de variables.

0
inger

J'ai quelques scripts Shell qui ont besoin de chercher des .properties et de les utiliser comme arguments de programmes que je n’ai pas écrits. Le cœur du script est une ligne comme celle-ci:

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

Effectivement, il s'agit de grep pour la clé et de filtrer les éléments avant les deux points et après tout hachage.

0
PanCrit

J'ai eu du succès avec

    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

Ceci est une solution qui analyse correctement les guillemets et se termine à un espace sans les guillemets. C'est sûr: aucune eval n'est utilisée.

J'utilise ce code dans mes fichiers .bashrc et .zshrc pour importer des variables à partir de scripts 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 }
  ' "$@"
}

Cela enregistre le nom de variable souhaité, puis déplace le tableau d'arguments afin que le reste puisse être passé sous forme de fichier à awk.

Comme il est très difficile d'appeler des variables Shell et de faire référence à des guillemets dans awk, je les définis en tant que variables awk sur la ligne de commande. Q est un caractère guillemet simple (apostrophe), QQ est un guillemet double et VAR est le premier argument que nous avons enregistré précédemment.

Pour plus de commodité, il existe deux fonctions d’aide. Le premier retourne l'emplacement du texte donné dans la ligne courante et le second imprime le contenu entre les deux premières guillemets de la ligne en utilisant le caractère guillemet d (pour "délimiteur"). Il existe une variable d dérivée concaténée à la première substr comme sécurité contre les chaînes multilignes (voir "Avertissements" ci-dessous).

Bien que j'ai écrit le code pour l'analyse syntaxique du shell POSIX, il semble que celui-ci ne diffère de votre format que par l'existence d'un espace blanc autour de la signature. Vous pouvez ajouter cette fonctionnalité au code ci-dessus en ajoutant sub(/[ \t]*=[ \t]*/, "="); avant sub(…) sur la ligne 4 de awk (remarque: la ligne 1 est vide).

La quatrième ligne supprime l’espace blanc au début et enregistre l’emplacement du premier signe égal. Vérifiez que votre awk prend en charge \t en tant qu'onglet, ce n'est pas garanti sur les anciens systèmes UNIX.

La ligne substr compare le texte précédant le signe égal à VAR. Si cela ne correspond pas, la ligne affecte une variable différente, nous la sautons donc et passons à la ligne suivante.

Nous savons maintenant que nous avons l'affectation de variable demandée. Il suffit donc de démêler les guillemets. Nous faisons cela en recherchant le premier emplacement de =" (ligne 6) ou =' (ligne 7) ou sans guillemets (ligne 8). Chacune de ces lignes imprime la valeur attribuée.

Mises en garde: s'il existe un caractère de citation échappé, nous lui renverrons une valeur tronquée. Détecter ceci est un peu non trivial et j'ai décidé de ne pas le mettre en œuvre. Il y a aussi un problème de guillemets multilignes, qui sont tronqués au premier saut de ligne (c'est le but de "stray d" mentionné ci-dessus). La plupart des solutions sur cette page souffrent de ces problèmes.

0
Adam Katz