web-dev-qa-db-ja.com

テンプレート化された読み取り(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を簡単に操作して、HostSHARE、およびPERIODを抽出し、sscanfテンプレートを派生させることができます。

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に飛び込むつもりなら、おそらくテンプレートの書き換えとsscanf生成をPerlの部分でも行うでしょうが、とりあえずそれを止めましょう。)

ただし、Perlを必要とするシェルスクリプトをいくらか書いてみませんか。

テンプレート内のかなり任意のラベルの文字列から値をマッピングできる代替の(より良い)ソリューションはありますか?

2
roaima

正規表現の使用はオプションですか?ただし、%...%(.*)に完全に置き換えるために、sedにShellで送信する必要がありました。

$ 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
muru

これでうまくいくはずです:

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

1
matsib.dev