web-dev-qa-db-ja.com

設定ファイルからアクセスするセクションごとの変数

以下に説明するように、セクションごとのデータを含む1つの構成ファイルがあります。各変数にアクセスするシェルスクリプトを使用する。そのためにsedコマンドを使用していますが、1つの変数example:name [APP1]を構成するのを忘れた場合など、1つの問題に直面しています。
構成ファイル:

[APP1]
name=Application1
StatusScript=/home/status_APP1.sh
startScript=/home/start_APP1.sh
stopScript=/home/stop_APP1.sh
restartScript=/home/restart.APP1.sh

[APP2]
name=Application2
StatusScript=/home/status_APP2.sh
startScript=/home/start_APP2.sh
stopScript=/home/stop_APP2.sh
restartScript=/home/restart.APP2.sh
logdir=/log/APP2/
.
.
.
.
.
[APPN]
name=ApplicationN
StatusScript=/home/status_APPN.sh
startScript=/home/start_APPN.sh
stopScript=/home/stop_APPN.sh
restartScript=/home/restart.APPN.sh
logdir=/log/APPN

:を使用するシェルコマンド

sed -nr "/^\[APP1\]/ { :l /^name[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}"

この問題を解決する方法はありますか?一部の変数が1つのセクションで構成されていない場合、変数値としてnullまたは0を使用します。

3
Arun Binoy

次のようなシェル関数を作成できます。

printSection()
{
  section="$1"
  found=false
  while read line
  do
    [[ $found == false && "$line" != "[$section]" ]] &&  continue
    [[ $found == true && "${line:0:1}" = '[' ]] && break
    found=true
    echo "$line"
  done
}

次に、コマンドのようにprintSectionを使用して、次のようにセクションをパラメータとして渡すことができます。

printSection APP2

パラメータを取得するには、次のように、はるかに単純なsedを使用できます。

printSection APP2 | sed -n 's/^name=//p'

これはstdinで動作し、stdoutに書き込みます。したがって、サンプル構成ファイルの名前が/etc/application.confで、APP2の名前を変数app2nameに保存したい場合は、次のように記述できます。

app2name=$(printSection APP2 | sed -n 's/^name//p/' < /etc/applications.conf)

または、次のように、パラメーター部分を関数に組み込み、sedを完全にスキップすることもできます。

printValue()
{
  section="$1"
  param="$2"
  found=false
  while read line
  do
    [[ $found == false && "$line" != "[$section]" ]] &&  continue
    [[ $found == true && "${line:0:1}" = '[' ]] && break
    found=true
    [[ "${line%=*}" == "$param" ]] && { echo "${line#*=}"; break; }
  done
}

次に、varを次のように割り当てます。

app2name=$(printValue APP2 name < /etc/applications.conf)
1
Scott Plante

構成を明確な形式に解析し、bashの最近のリリースで連想配列に読み取ります。

awk '/^\[/ { app=substr($0,2,length-2) } /=/ { print app "." $0 }' file.conf

これにより、すべてのセクションヘッダーが検索され、awk変数appにこれらの内容が設定されます。次に、後続の各行の先頭にその値の後にドットを付けます。

これは次のような出力を作成します

APP1.name=Application1
APP1.StatusScript=/home/status_APP1.sh
APP1.startScript=/home/start_APP1.sh
APP1.stopScript=/home/stop_APP1.sh
APP1.restartScript=/home/restart.APP1.sh
APP2.name=Application2
APP2.StatusScript=/home/status_APP2.sh
APP2.startScript=/home/start_APP2.sh
APP2.stopScript=/home/stop_APP2.sh
APP2.restartScript=/home/restart.APP2.sh
APP2.logdir=/log/APP2/

もしあなたの APP2にはnameサブセクションがありませんでした、APP2.name行は表示されません。

次に、これをbashの連想配列に読み込みます。

declare -A conf
while IFS='=' read -r key value; do
    conf[$key]="$value"
done < <(awk '/^\[/ { app=substr($0,2,length-2) } /=/ { print app "." $0 }' file.conf)

これで、conf変数を照会して構成を確認できます。

printf 'The stopScript for APPN is "%s"\n' "${conf[APPN.stopScript]}"

これは戻ります

The stopScript for APPN is "/home/stop_APPN.sh"

存在しない値をクエリすると、空の文字列が生成されます。


awkコマンドは、次のsedコマンドで置き換えることもできます。

sed -n \
    -e '/^\[/{s/[][]//g;h;}' \
    -e '/=/{H;g;s/\n/./;p;s/\..*//;h;}' file.conf

展開および注釈付き:

/^\[/{          # handle section headers
    s/[][]//g;  # remove [ and ]
    h;          # put into the hold-space
}

/=/{            # handle settings
    H;          # append the line to the hold-space with newline as delimiter
    g;          # get the hold-space
    s/\n/./;    # replace the newline with a dot
    p;          # output
    s/\..*//;   # remove everything after the dot
    h;          # put back into the hold-space
}
3
Kusalananda