現在、次のように定義されているシェルスクリプト変数があります。
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
、SHARE
、および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
を必要とするシェルスクリプトをいくらか書いてみませんか。
テンプレート内のかなり任意のラベルの文字列から値をマッピングできる代替の(より良い)ソリューションはありますか?
正規表現の使用はオプションですか?ただし、%...%
を(.*)
に完全に置き換えるために、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
これでうまくいくはずです:
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