テンプレートベースの読み取り(例:scanf)

テンプレートベースの読み取り(例:scanf)

現在、次のように定義されたシェルスクリプト変数があります。

tsource=/backup/%HOST%/%SHARE%/%PERIOD%

このテンプレートを次の値を持つことができる他の変数と一致させたいと思います。

psource=/backup/somehost/someshare/monthly.1

私の目標は、後で置き換えのためにスクリプトで使用できるように、次の割り当てを作成することです。

vars[HOST]=somehost
vars[SHARE]=someshare
vars[PERIOD]=monthly.1

ユーザーは両方の値をオーバーライドでき、結果として異なる(しかしまだ一致する)外観が表示される可能性があることを指摘する必要があります。これは、単純な「分割/」(または「分割句読点」)だけでは十分ではないことを意味します。

tsource=/backup/%PERIOD/where/%HOST%-%SHARE%
psource=/backup/monthly.1/where/somehost-someshare

目的は、$psource提供されたテンプレートに基づいて解析できるようにすることです$tsource。ユーティリティソフトウェアなので、ユーザーがそれを壊そうとしても問題はありません。引数が不足しているか、無効な引数が指定された場合、後で終了します。

考えられる解決策を見て、似たようなものがsscanfここで役に立つと思いました。ここに間接的に使用できるツールがあります。テンプレートを簡単に$tsource抽出しHOSTて派生できます。SHAREPERIODsscanf

grep -Po "(?<=%)[[:upper:]]+(?=%)" <<<"$tsource"           # "HOST" "SHARE" "PERIOD"
tscanf=$(sed -re 's/%[[:upper:]]+%/%s/g' <<<"$tsource")    # "/backup/%s/%s/%s"

これにより、次の例のようにPerlでテンプレートを適用できます。

perl -MString::Scanf -e '
    $psource = "/backup/somehost/someshare/monthly.1";
    $tscanf = "/backup/%s/%s/%s";
    ($host, $source, $period) = sscanf($tscanf, $psource);
    print "host=$host, share=$share, period=$period\n"
'
# "host=somehost, share=someshare, period=monthly.1"

(Perlをより深く掘り下げると、sscanfPerlセクションでもテンプレートの書き換えと作成ができますが、今はその部分を取り除きます。)

しかし、書くにはperl

Perlをすばやく使用せずに文字列の値をテンプレート内の任意のタグにマッピングするための代替(より良い)ソリューションはありますか?

答え1

正規表現を使用するのはオプションですか?しかし、次にきれいにsed交換するには、まだ支出が必要です。%...%(.*)

$ psource=/backup/monthly.1/where/somehost-someshare
$ tsource=/backup/%PERIOD%/where/%HOST%-%SHARE%
$ # replace labels with '(.*)', need sed to avoid greediness of * in ${../../..}
$ tsource_re=$(sed 's/%[^%]*%/(.*)/g' <<<"${tsource}")
$ # match against tsource to get template names
$ [[ $tsource =~ $tsource_re ]]; tmatch=(${BASH_REMATCH[@]:1})
$ # match against psource to get template values
$ [[ $psource =~ $tsource_re ]]; pmatch=(${BASH_REMATCH[@]:1})
$ for i in ${!tmatch[@]}; do printf "%s:\t%s\n" "${tmatch[$i]}" "${pmatch[$i]}"; done
%PERIOD%:   monthly.1
%HOST%: somehost
%SHARE%:    someshare

答え2

これにより、トリックを実行できます。

tsource='/backup/%HOST%/%SHARE%/%PERIOD%'
psource='/backup/somehost/someshare/monthly.1'
IFS=$'\n' read -d '' -ra var_names <<< $(grep -Po "(?<=%)[[:upper:]]+(?=%)" <<< "$tsource")
IFS='/' read -ra var_values <<< $(echo ${psource#/*/})
declare -A vars=( ["${var_names[0]}"]="${var_values[0]}" ["${var_names[1]}"]="${var_values[1]}" ["${var_names[2]}"]="${var_values[2]}" )

echo ${vars[HOST]} ${vars[SHARE]} ${vars[PERIOD]}

>somehost someshare monthly.1

関連情報