web-dev-qa-db-fra.com

Comment lire un fichier .properties contenant des clés ayant un caractère de période à l'aide d'un script Shell

J'essaie de lire un fichier de propriétés à partir d'un script Shell qui contient un caractère point (.) Comme ci-dessous:

# app.properties
db.uat.user=saple user
db.uat.passwd=secret


#/bin/sh
function pause(){
   read -p "$*"
}

file="./app.properties"

if [ -f "$file" ]
then
    echo "$file found."
 . $file

echo "User Id " $db.uat.user
echo "user password =" $db.uat.passwd
else
    echo "$file not found."
fi

J'ai essayé d'analyser le fichier après l'avoir recherché, mais cela ne fonctionne pas, car les clés contiennent le "." caractère et il y a des espaces dans cette valeur aussi.

Mon fichier de propriétés réside toujours dans le même répertoire du script ou quelque part dans/usr/share/doc

39
Kiran

Comme les variables Shell (Bourne) ne peuvent pas contenir de points, vous pouvez les remplacer par des traits de soulignement. Lisez chaque ligne, traduisez. dans la clé pour _ et évaluer.

#/bin/sh

file="./app.properties"

if [ -f "$file" ]
then
  echo "$file found."

  while IFS='=' read -r key value
  do
    key=$(echo $key | tr '.' '_')
    eval ${key}=\${value}
  done < "$file"

  echo "User Id       = " ${db_uat_user}
  echo "user password = " ${db_uat_passwd}
else
  echo "$file not found."
fi

Notez que ce qui précède ne traduit que. Pour _, si vous avez un format plus complexe, vous pouvez utiliser des traductions supplémentaires. J'ai récemment dû analyser un fichier de propriétés Ant complet avec beaucoup de caractères désagréables, et je devais utiliser:

key=$(echo $key | tr .-/ _ | tr -cd 'A-Za-z0-9_')
42
fork2execve

J'utilise une simple fonction grep dans le script bash pour recevoir les propriétés de .properties fichier.

Ce fichier de propriétés que j'utilise à deux endroits - pour configurer l'environnement dev et comme paramètres d'application.

Je crois que grep peut fonctionner lentement dans les grandes boucles, mais cela résout mes besoins lorsque je veux préparer l'environnement dev.

J'espère que quelqu'un trouvera cela utile.

Exemple:

Fichier: setup.sh

#!/bin/bash

ENV=${1:-dev}

function prop {
    grep "${1}" env/${ENV}.properties|cut -d'=' -f2
}

docker create \
    --name=myapp-storage \
    -p $(prop 'app.storage.address'):$(prop 'app.storage.port'):9000 \
    -h $(prop 'app.storage.Host') \
    -e STORAGE_ACCESS_KEY="$(prop 'app.storage.access-key')" \
    -e STORAGE_SECRET_KEY="$(prop 'app.storage.secret-key')" \
    -e STORAGE_BUCKET="$(prop 'app.storage.bucket')" \
    -v "$(prop 'app.data-path')/storage":/app/storage \
    myapp-storage:latest

docker create \
    --name=myapp-database \
    -p "$(prop 'app.database.address')":"$(prop 'app.database.port')":5432 \
    -h "$(prop 'app.database.Host')" \
    -e POSTGRES_USER="$(prop 'app.database.user')" \
    -e POSTGRES_PASSWORD="$(prop 'app.database.pass')" \
    -e POSTGRES_DB="$(prop 'app.database.main')" \
    -e PGDATA="/app/database" \
    -v "$(prop 'app.data-path')/database":/app/database \
    postgres:9.5

Fichier: env/dev.properties

app.data-path=/apps/myapp/

#==========================================================
# Server properties
#==========================================================
app.server.address=127.0.0.70
app.server.Host=dev.myapp.com
app.server.port=8080

#==========================================================
# Backend properties
#==========================================================
app.backend.address=127.0.0.70
app.backend.Host=dev.myapp.com
app.backend.port=8081
app.backend.maximum.threads=5

#==========================================================
# Database properties
#==========================================================
app.database.address=127.0.0.70
app.database.Host=database.myapp.com
app.database.port=5432
app.database.user=dev-user-name
app.database.pass=dev-password
app.database.main=dev-database

#==========================================================
# Storage properties
#==========================================================
app.storage.address=127.0.0.70
app.storage.Host=storage.myapp.com
app.storage.port=4569
app.storage.endpoint=http://storage.myapp.com:4569
app.storage.access-key=dev-access-key
app.storage.secret-key=dev-secret-key
app.storage.region=us-east-1
app.storage.bucket=dev-bucket

Usage:

./setup.sh dev
60
Nicolai

Comme les noms de variables dans le shell BASH ne peuvent pas contenir de point ou d'espace, il est préférable d'utiliser un tableau associatif dans BASH comme ceci:

#!/bin/bash

# declare an associative array
declare -A arr

# read file line by line and populate the array. Field separator is "="
while IFS='=' read -r k v; do
   arr["$k"]="$v"
done < app.properties

Test:

Utilisez declare -p pour afficher le résultat:

  > declare -p arr  

        declare -A arr='([db.uat.passwd]="secret" [db.uat.user]="saple user" )'
10
anubhava

J’ai trouvé que l’utilisation de while IFS='=' read -r Était un peu lente (je ne sais pas pourquoi, peut-être que quelqu'un pourrait expliquer brièvement dans un commentaire ou indiquer un SO réponse?). @Nicolai a trouvé une réponse très soignée en une ligne, mais très inefficace, car elle analysera tout le fichier de propriétés à chaque fois pour chaque appel de prop.

J'ai trouvé une solution qui répond à la question, fonctionne bien et c'est un one-liner (bit verbose line).

La solution effectue le sourcing mais masse le contenu avant le sourcing:

#!/usr/bin/env bash

source <(grep -v '^ *#' ./app.properties | grep '[^ ] *=' | awk '{split($0,a,"="); print gensub(/\./, "_", "g", a[1]) "=" a[2]}')

echo $db_uat_user

Explication:

grep -v '^ *#': Ignore les lignes de commentaires grep '[^ ] *=': Supprime les lignes sans =split($0,a,"="): divise la ligne à = Et la stocke dans le tableau a, ie un [1] est la clé, un [2] est la valeur gensub(/\./, "_", "g", a[1]): remplace . par _print gensub... "=" a[2]} concatène le résultat de gensub ci-dessus avec = et de la valeur.

Edit: Comme d'autres l'ont souligné, il existe des problèmes d'incompatibilités (awk) et ne valide pas le contenu pour voir si chaque ligne du fichier de propriétés est en réalité une paire kv. Mais le but ici est de montrer l’idée générale d’une solution à la fois rapide et propre. Le sourcing semble être la solution, car il charge les propriétés une fois pouvant être utilisées plusieurs fois.

1
L. Holanda

@ fork2x

J'ai essayé comme ça. S'il vous plaît examiner et me mettre à jour si c'est la bonne approche ou non.

#/bin/sh
function pause(){
   read -p "$*"
}

file="./apptest.properties"


if [ -f "$file" ]
then
    echo "$file found."

dbUser=`sed '/^\#/d' $file | grep 'db.uat.user'  | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'`
dbPass=`sed '/^\#/d' $file | grep 'db.uat.passwd'  | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'`

echo database user = $dbUser
echo database pass = $dbPass

else
    echo "$file not found."
fi
0
Kiran