programing

배시 템플릿:Bash를 사용하여 템플릿에서 구성 파일을 작성하는 방법

megabox 2023. 4. 19. 22:52
반응형

배시 템플릿:Bash를 사용하여 템플릿에서 구성 파일을 작성하는 방법

Apache 및 PHP용 구성 파일 생성을 자동화하는 스크립트를 작성하고 있습니다.CPanel이나 ISPConfig 등의 GUI는 사용하고 싶지 않습니다.

Apache 및 PHP 구성 파일 템플릿이 있습니다.Bash 스크립트는 템플릿을 읽고 변수를 대체하며 구문 분석된 템플릿을 일부 폴더에 출력해야 합니다.그것을 하는 가장 좋은 방법은?몇 가지 방법을 생각할 수 있습니다.어떤 것이 가장 좋습니까, 아니면 더 나은 방법이 있을까요?순수한 Bash로 하고 싶다(예를 들어 PHP에서는 쉽다)

  1. 텍스트 파일에서 ${} 자리 표시자를 바꾸려면 어떻게 해야 합니까?

템플릿입니다.txt:

The number is ${i}
The word is ${word}

script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

그런데 여기서 출력을 외부 파일로 리다이렉트하려면 어떻게 해야 하나요?변수에 따옴표가 포함되어 있는 경우, 뭔가 이스케이프할 필요가 있습니까?

  1. 각 변수를 값으로 대체하기 위해 cat & sed 사용:

지정된 템플릿txt(위 참조)

명령어:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

많은 다른 기호에서 벗어나야 하고 변수가 많아서 줄이 너무 길어서 안 좋은 것 같습니다.

당신은 다른 우아하고 안전한 해결책을 생각할 수 있나요?

시험해 보다

$ cat envsubst-template.txt
Variable FOO is (${FOO}).
Variable BAR is (${BAR}).

$ FOO=myfoo

$ BAR=mybar

$ export FOO BAR

$ cat envsubst-template.txt | envsubst
Variable FOO is (myfoo).
Variable BAR is (mybar).

세습은 컨피규레이션파일을 템플릿으로 하는 임베디드 방법입니다.

STATUS_URI="/hows-it-goin";  MONITOR_IP="10.10.2.15";

cat >/etc/apache2/conf.d/mod_status.conf <<EOF
<Location ${STATUS_URI}>
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from ${MONITOR_IP}
</Location>
EOF

Yottsa의 답변에 대해서:envsubst 멋지다.상적적환

다음을 사용할 수 있습니다.

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

${...}대응하는 환경변수가 있는 문자열(이 스크립트를 실행하기 전에 그것들을 내보내는 것을 잊지 말아 주세요).

순수 bash의 경우, 이것은 동작합니다(변수에 ${...가 포함되어 있지 않다고 가정합니다).} 문자열:

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

RHS가 자신을 참조하는 변수를 참조하는 경우 중단되지 않는 솔루션:

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

경고: bash에서 NUL을 사용하여 입력을 올바르게 처리하거나 줄 바꿈의 양을 유지하는 방법을 알 수 없습니다.마지막 변형은 셸이 "love" 바이너리 입력이기 때문에 그대로 표시됩니다.

  1. read을 사용하다
  2. read -r는 백슬래시를 해석하지 않지만 새 행으로 끝나지 않으면 마지막 행을 드롭합니다.
  3. "$(…)" 행이 합니다.; echo -n a를 사용합니다.echo -n "${line:0:-1}", 「」)가 드롭 됩니다.a)와 같은 수의 후행 새 행을 입력합니다(no 포함).

sed 사용에 동의합니다. 검색/교체를 위한 최고의 도구입니다.저의 접근방식은 다음과 같습니다.

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido

모지 같은 bash 솔루션이 있지만 이중 따옴표를 피할 수 있도록 이 스트링 대신 유전적인 솔루션을 사용합니다.

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

평가판 사용

생각에는eval정말 잘 작동합니다.줄 바꿈, 공백 및 모든 종류의 bash 항목이 포함된 템플릿을 처리합니다.템플릿 자체를 완전히 제어할 수 있는 경우 다음을 수행합니다.

$ cat template.txt
variable1 = ${variable1}
variable2 = $variable2
my-ip = \"$(curl -s ifconfig.me)\"

$ echo $variable1
AAA
$ echo $variable2
BBB
$ eval "echo \"$(<template.txt)\"" 2> /dev/null
variable1 = AAA
variable2 = BBB
my-ip = "11.22.33.44"

물론 eval은 임의의 코드를 실행할 수 있기 때문에 이 메서드는 신중하게 사용해야 합니다.이것을 루트로 실행하는 것은 거의 불가능하다. 따옴표는 않으면 따옴표를 할 수 .스케이프하지 않으면 이 따옴표를 사용할 수 없습니다.eval.

를 사용할 .cat로로 합니다.echo

$ eval "cat <<< \"$(<template.txt)\"" 2> /dev/null

@plockc는 bash 인용이 문제를 회피하는 솔루션을 프로비저닝했습니다.

$ eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

편집: sudo를 사용하여 루트로 실행하는 부분 제거...

편집: 견적을 이스케이프하는 방법에 대한 코멘트를 추가하고 혼합물에 Plockc 솔루션을 추가했습니다.

2017년 1월 6일 편집

설정 파일에 큰따옴표를 붙여야 했기 때문에 sed를 사용하면 큰따옴표를 피하면 다음과 같이 도움이 됩니다.

render_template() {
  eval "echo \"$(sed 's/\"/\\\\"/g' $1)\""
}

새 줄을 계속 이어갈 생각은 없지만, 그 사이에 빈 줄이 남아 있습니다.


오래된 토픽이지만 IMO 저는 여기서 보다 우아한 솔루션을 발견했습니다.http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/

#!/bin/sh

# render a template configuration file
# expand variables + preserve formatting
render_template() {
  eval "echo \"$(cat $1)\""
}

user="Gregory"
render_template /path/to/template.txt > path/to/configuration_file

모든 크레딧은 그레고리 파코즈입니다

휠을 재창조하는 대신 envsubst를 사용하여 도커 컨테이너의 환경 변수에서 구성 파일을 구축하는 등 거의 모든 시나리오에서 사용할 수 있습니다.

Mac의 경우 홈브루가 있는지 확인하고 gettext에서 링크합니다.

brew install gettext
brew link --force gettext

./cfg.cfg

# We put env variables into placeholders here
this_variable_1 = ${SOME_VARIABLE_1}
this_variable_2 = ${SOME_VARIABLE_2}

./.env:

SOME_VARIABLE_1=value_1
SOME_VARIABLE_2=value_2

./configure(설정.

#!/bin/bash
cat template.cfg | envsubst > whatever.cfg

지금 바로 사용하세요.

# make script executable
chmod +x ./configure.sh
# source your variables
. .env
# export your variables
# In practice you may not have to manually export variables 
# if your solution depends on tools that utilise .env file 
# automatically like pipenv etc. 
export SOME_VARIABLE_1 SOME_VARIABLE_2
# Create your config file
./configure.sh

효율은 떨어지지만 읽기/유지관리는 더 쉽기 때문에 이런 식으로 했을 것입니다.

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE

Jinja2 템플릿을 사용하려면 j2cli 프로젝트를 참조하십시오.

지원 대상:

  • JSON, INI, YAML 파일 및 입력 스트림 템플릿
  • 환경변수로 템플릿 작성

승인된 답변의 보다 길고 견고한 버전:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})?;substr($1,0,int(length($1)/2)).($2&&length($1)%2?$2:$ENV{$3||$4});eg' template.txt

가 확장됩니다.$VAR or or or openicle. ${VAR}환경 값(또는 정의되지 않은 경우 빈 문자열)으로 이동합니다.

백슬래시를 적절히 회피하고 백슬래시 이스케이프된 달러를 받아 들여 대체를 금지합니다(Envsubst와는 달리, 실제로는 그렇지 않습니다).

고객의 환경이 다음과 같은 경우:

FOO=bar
BAZ=kenny
TARGET=backslashes
NOPE=engi

템플릿은 다음과 같습니다.

Two ${TARGET} walk into a \\$FOO. \\\\
\\\$FOO says, "Delete C:\\Windows\\System32, it's a virus."
$BAZ replies, "\${NOPE}s."

결과는 다음과 같습니다.

Two backslashes walk into a \bar. \\
\$FOO says, "Delete C:\Windows\System32, it's a virus."
kenny replies, "${NOPE}s."

$ 전에 백슬래시를 이스케이프하는 경우(C:\Windows\템플릿의 System32")는 다음과 같이 약간 변경된 버전을 사용합니다.

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\});substr($1,0,int(length($1)/2)).(length($1)%2?$2:$ENV{$3||$4});eg' template.txt

다음은 순수 bash 솔루션입니다.

  • 유전체를 사용하니까
    • 추가 필수 구문 때문에 복잡성이 증가하지 않음
    • 쾅쾅거리다
      • 또한 올바르게 삽입할 수 있습니다.이하를 참조해 주세요.
  • eval:
    • 빈 줄의 후행 렌더링에 문제가 없음
    • 템플릿에 따옴표 문제가 없습니다.

$ cat code

#!/bin/bash
LISTING=$( ls )

cat_template() {
  echo "cat << EOT"
  cat "$1"
  echo EOT
}

cat_template template | LISTING="$LISTING" bash

력::
$ cat template의 줄 (「」)

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
$( echo "$LISTING" | sed 's/^/        /' )
      <pre>
    </p>
  </body>
</html>

출력:

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
        code
        template
      <pre>
    </p>
  </body>
</html>

다음으로 모든 변수와 템플릿파일의 내용을 포함하는 bash 스크립트를 생성합니다.이 스크립트는 다음과 같습니다.

word=dog           
i=1                
cat << EOF         
the number is ${i} 
the word is ${word}

EOF                

이 스크립트를 bash에 입력하면 원하는 출력이 생성됩니다.

the number is 1
the word is dog

다음으로 스크립트를 생성하여 bash에 입력하는 방법을 나타냅니다.

(
    # Variables
    echo word=dog
    echo i=1

    # add the template
    echo "cat << EOF"
    cat template.txt
    echo EOF
) | bash

논의

  • 괄호는 하위 셸을 열며, 생성된 모든 출력을 그룹화하는 것을 목적으로 합니다.
  • 서브셸 내에서 모든 변수 선언을 생성합니다.
  • 에서는 「」를 합니다.catGREENDOC
  • 마지막으로 서브셸 출력을 bash에 공급하여 원하는 출력을 생성합니다.
  • 이 출력을 파일로 리디렉션하려면 마지막 행을 다음과 같이 바꿉니다.

    ) | bash > output.txt
    

순수 bash를 사용하여 ZyX의 답변을 얻지만 새로운 스타일의 regex 매칭과 간접 파라미터 치환을 사용하면 다음과 같이 됩니다.

#!/bin/bash
regex='\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}'
while read line; do
    while [[ "$line" =~ $regex ]]; do
        param="${BASH_REMATCH[1]}"
        line=${line//${BASH_REMATCH[0]}/${!param}}
    done
    echo $line
done

Perl을 사용하는 것이 옵션이고 (모든 셸 변수가 아닌) 환경 변수만을 기반으로 한 확장에 만족하는 경우 Stuart P를 고려하십시오. 벤틀리의 힘찬 답변.

이 답변은 bash 전용 솔루션을 제공하는 것을 목적으로 하고 있습니다.eval- 사용하기에 안전해야 합니다.

목표는 다음과 같습니다.

  • 확장 ${name} ★★★★★★★★★★★★★★★★★」$name변수 참조
  • 다음과 같이 합니다.
    • 치환명령어 치환)$(...) 구문 " " " "`...`
    • 치환$((...)) 구문 " " " "$[...]를 참조해 주세요.
  • 확장을 선택적으로 할 수 .\ )\${name}를 참조해 주세요.
  • , 특히 입력의 경우" ★★★★★★★★★★★★★★★★★」\인스턴스.
  • 인수를 통한 입력 또는 stdin을 통한 입력을 허용합니다.

기능:

expandVars() {
  local txtToEval=$* txtToEvalEscaped
  # If no arguments were passed, process stdin input.
  (( $# == 0 )) && IFS= read -r -d '' txtToEval
  # Disable command substitutions and arithmetic expansions to prevent execution
  # of arbitrary commands.
  # Note that selectively allowing $((...)) or $[...] to enable arithmetic
  # expressions is NOT safe, because command substitutions could be embedded in them.
  # If you fully trust or control the input, you can remove the `tr` calls below
  IFS= read -r -d '' txtToEvalEscaped < <(printf %s "$txtToEval" | tr '`([' '\1\2\3')
  # Pass the string to `eval`, escaping embedded double quotes first.
  # `printf %s` ensures that the string is printed without interpretation
  # (after processing by by bash).
  # The `tr` command reconverts the previously escaped chars. back to their
  # literal original.
  eval printf %s "\"${txtToEvalEscaped//\"/\\\"}\"" | tr '\1\2\3' '`(['
}

예:

$ expandVars '\$HOME="$HOME"; `date` and $(ls)'
$HOME="/home/jdoe"; `date` and $(ls)  # only $HOME was expanded

$ printf '\$SHELL=${SHELL}, but "$(( 1 \ 2 ))" will not expand' | expandVars
$SHELL=/bin/bash, but "$(( 1 \ 2 ))" will not expand # only ${SHELL} was expanded
  • 성능상의 이유로 함수는 stdin 입력을 메모리로 한꺼번에 읽어들이지만, 함수를 한 줄 한 줄 접근법에 맞게 쉽게 조정할 수 있습니다.
  • 다음과 같은 비기본 변수 확장도 지원합니다.${HOME:0:10} 또는 (예: " " " " "」는 를 참조해 주세요.${HOME:0:$(echo 10)}
    • 것이 BREAK입니다).$( ★★★★★★★★★★★★★★★★★」`인스턴스는 맹목적으로 이스케이프됩니다).
    • "" "부정형 변수 참조" 입니다.${HOME(최종마감(폐쇄)} 합니다 기능을 정지합니다.
  • bash는 이중 따옴표로 묶인 문자열을 처리하므로 백슬래시는 다음과 같이 처리됩니다.
    • \$name을 사용하다
    • ★★★\ 없다$그대로 보존됩니다.
    • 인접한 여러 개를 나타내는 경우 \인스턴스(instance)는 두 로 해야 합니다. 예:
      • \\->\ - 똑같아\
      • \\\\->\\
    • 에는 내부수 .0x1,0x2,0x3.
  • 구문을 이가 이러한 막지 수 bash를 .사용하지 않는 솔루션에 대해서는, 이하를 참조해 주세요.eval.

확장만 지원하는 보다 제한적인 솔루션을 찾고 있는 경우(예: 필수 중괄호 포함, 무시)$name참고 자료 - 이 답변을 참조하십시오.


다음 수용된 답변에서 개선된 bash-only-free 솔루션 버전입니다.

개선점은 다음과 같습니다.

  • 확장 ${name} ★★★★★★★★★★★★★★★★★」$name변수 참조
  • 원원의 \-확장되지않는변수참조를표시합니다.
  • 「 」와 eval- 아, 아, 아,
    • 기본이 아닌 확장은 무시됩니다.
    • 잘못된 형식의 변수 참조는 무시됩니다(스크립트가 깨지지 않음).
 IFS= read -d '' -r lines # read all input from stdin at once
 end_offset=${#lines}
 while [[ "${lines:0:end_offset}" =~ (.*)\$(\{([a-zA-Z_][a-zA-Z_0-9]*)\}|([a-zA-Z_][a-zA-Z_0-9]*))(.*) ]] ; do
      pre=${BASH_REMATCH[1]} # everything before the var. reference
      post=${BASH_REMATCH[5]}${lines:end_offset} # everything after
      # extract the var. name; it's in the 3rd capture group, if the name is enclosed in {...}, and the 4th otherwise
      [[ -n ${BASH_REMATCH[3]} ]] && varName=${BASH_REMATCH[3]} || varName=${BASH_REMATCH[4]}
      # Is the var ref. escaped, i.e., prefixed with an odd number of backslashes?
      if [[ $pre =~ \\+$ ]] && (( ${#BASH_REMATCH} % 2 )); then
           : # no change to $lines, leave escaped var. ref. untouched
      else # replace the variable reference with the variable's value using indirect expansion
           lines=${pre}${!varName}${post}
      fi
      end_offset=${#pre}
 done
 printf %s "$lines"

이 페이지에 있는 Plockc의 답변에 대한 후속 조치를 위해, 여기 bashism을 피하고 싶은 분들을 위해 대시 대응 버전이 있습니다.

eval "cat <<EOF >outputfile
$( cat template.in )
EOF
" 2> /dev/null

shtpl을 시도

shtpl에 딱 맞는 케이스입니다.(프로젝트이기 때문에 널리 사용되고 있지 않고 문서도 부족합니다.)하지만 어쨌든 여기에 해결책이 있습니다.테스트해 보시기 바랍니다.)

실행:

$ i=1 word=dog sh -c "$( shtpl template.txt )"

결과는 다음과 같습니다.

the number is 1
the word is dog

즐겁게 보내세요.

이 페이지에서는 awk와 함께 답변에 대해 설명합니다.

awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < input.txt > output.txt
# Usage: template your_file.conf.template > your_file.conf
template() {
        local IFS line
        while IFS=$'\n\r' read -r line ; do
                line=${line//\\/\\\\}         # escape backslashes
                line=${line//\"/\\\"}         # escape "
                line=${line//\`/\\\`}         # escape `
                line=${line//\$/\\\$}         # escape $
                line=${line//\\\${/\${}       # de-escape ${         - allows variable substitution: ${var} ${var:-default_value} etc
                # to allow arithmetic expansion or command substitution uncomment one of following lines:
#               line=${line//\\\$\(/\$\(}     # de-escape $( and $(( - allows $(( 1 + 2 )) or $( command ) - UNSECURE
#               line=${line//\\\$\(\(/\$\(\(} # de-escape $((        - allows $(( 1 + 2 ))
                eval "echo \"${line}\"";
        done < "$1"
}

이것은 기호에 따라 조정할 수 있는 순수 bash 기능으로, 생산에 사용되며 입력 시 끊어지지 않습니다.고장나면 알려주세요.

또한 bashible을 사용할 수도 있습니다(상기/아래에서 설명한 평가 방법을 내부적으로 사용).

예를 들어 여러 부분에서HTML을 생성하는 방법이 있습니다.

https://github.com/mig1984/bashible/tree/master/examples/templates

간단한 변수 대체 python 스크립트를 참조하십시오.https://github.com/jeckep/vsubst

사용법은 매우 간단합니다.

python subst.py --props secure.properties --src_path ./templates --dst_path ./dist

공백 공간을 보존하는 bash 함수는 다음과 같습니다.

# Render a file in bash, i.e. expand environment variables. Preserves whitespace.
function render_file () {
    while IFS='' read line; do
        eval echo \""${line}"\"
    done < "${1}"
}

여기 요.perl기타 몇 가지 답변을 바탕으로 스크립트를 작성합니다.

perl -pe 's/([^\\]|^)\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}/$1.$ENV{$2}/eg' -i template

기능(요구에 따라 다르지만 쉽게 수정할 수 있어야 함):

  • 이스케이프된 파라미터 확장을 건너뜁니다(예: \${VAR}).
  • ${VAR} 형식의 매개 변수 확장을 지원하지만 $VAR 형식은 지원하지 않습니다.
  • VAR 환경이 없는 경우 ${VAR}을(를) 빈 문자열로 바꿉니다.
  • 이름에 a-z, A-Z, 0-9 및 밑줄 문자만 지원합니다(첫 번째 위치의 숫자는 제외).

printf를 사용하여 템플릿을 채울 수도 있습니다.

#!/bin/bash

IFS='' read -rd '' TEMPL <<-'EOB'
The number is %d
The word is "%s"
Birds of Massachusetts:
    %s




EOB

N=12
WORD="Bird"
MULTILINE="Eastern Bluebirds
Common Grackles"

echo "START"
printf "${TEMPL}" ${N} ${WORD} "${MULTILINE}"
echo "END"

출력은 다음과 같습니다.따옴표와 공백은 그대로입니다.

START
The number is 12
The word is "Bird"
Birds of Massachusetts:
    Eastern Bluebirds
Common Grackles




END

언급URL : https://stackoverflow.com/questions/2914220/bash-templating-how-to-build-configuration-files-from-templates-with-bash

반응형