web-dev-qa-db-ja.com

シェルスクリプトを使用して、ピリオド文字を含むキーを含む.propertiesファイルを読み取る方法

次のようなピリオド(。)文字を含むシェルスクリプトからプロパティファイルを読み取ろうとしています。

# 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

ファイルを入手した後にファイルを解析しようとしましたが、キーに「。」が含まれているため機能しません。文字とその値にもスペースがあります。

プロパティファイルは常にスクリプトの同じディレクトリまたは/ usr/share/docのどこかにあります

39
Kiran

(Bourne)シェル変数にはドットを含めることができないため、ドットをアンダースコアに置き換えることができます。すべての行を読み、翻訳します。 _のキーで評価します。

#/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

上記は翻訳するだけであることに注意してください。より複雑な形式がある場合は、追加の翻訳を使用できます。私は最近、多くの厄介な文字を含む完全なAntプロパティファイルを解析する必要があり、そこで使用する必要がありました。

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

単純なgrepをbashスクリプトの関数内で使用して、.propertiesファイルからプロパティを受け取ります。

このプロパティファイルは、開発環境をセットアップするためとアプリケーションパラメータとして使用する2つの場所で使用します。

grepは大きなループでは動作が遅いと思われますが、dev環境を準備したい場合のニーズは解決します。

誰かがこれが役に立つことを願っています。

例:

ファイル: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

ファイル: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

使用法:

./setup.sh dev
60
Nicolai

BASHシェルの変数名にはドットやスペースを含めることができないため、次のようにBASHで連想配列を使用することをお勧めします。

#!/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

テスト:

Declare -pを使用して結果を表示します。

  > declare -p arr  

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

while IFS='=' read -rの使用が少し遅いことがわかりました(理由はわかりません。誰かがコメントで簡単に説明したり、SOの回答を指したりするかもしれません)。また、@ Nicolaiはワンライナーとして非常にきちんとした答えを見つけましたが、propの呼び出しごとにプロパティファイル全体を何度もスキャンするため、非常に非効率的です。

私は質問に答え、うまく機能し、ワンライナーであるソリューションを見つけました(しかし、ビット冗長なライン)。

ソリューションはソーシングを行いますが、ソーシングの前にコンテンツをマッサージします。

#!/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

説明:

grep -v '^ *#':コメント行を破棄grep '[^ ] *='=なしの行を破棄split($0,a,"=")=で行を分割し、配列aに格納します。つまり、a [1]はキー、a [2]は値gensub(/\./, "_", "g", a[1])._に置き換えますprint gensub... "=" a[2]}は、上記のgensubの結果を=と値に連結します。

編集:他の人が指摘したように、いくつかの非互換性の問題(awk)があり、プロパティファイルのすべての行が実際にkvペアであるかどうかを確認するために内容を検証しません。ただし、ここでの目標は、高速でクリーンなソリューションの一般的なアイデアを示すことです。ソーシングは、複数回使用できるプロパティを一度ロードするための方法のようです。

1
L. Holanda

@ fork2x

私はこのようにしてみました。それが正しいアプローチであるかどうかを確認し、更新してください。

#/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