템플릿 기반 읽기(예: 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

관련 정보