現在、次のように定義されたシェルスクリプト変数があります。
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
。
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