[bash] Bash Templating : Bash를 사용하여 템플릿에서 구성 파일을 작성하는 방법은 무엇입니까?

내 웹 서버의 Apache 및 PHP 구성 파일 작성을 자동화하는 스크립트를 작성 중입니다. CPanel 또는 ISPConfig와 같은 GUI를 사용하고 싶지 않습니다.

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

1) 텍스트 파일에서 $ {} 자리 표시자를 바꾸는 방법은 무엇입니까?

template.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"

BTW, 출력을 외부 파일로 어떻게 리디렉션합니까? 변수에 따옴표가 포함되어 있으면 무언가를 피해야합니까?

2) cat & sed를 사용하여 각 변수를 값으로 대체하십시오.

주어진 template.txt :

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

명령:

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

많은 다른 기호를 벗어날 필요가 있고 나에게 많은 변수가 있기 때문에 선이 길어질 것 같습니다.

우아하고 안전한 다른 솔루션을 생각할 수 있습니까?



답변

이것을 사용할 수 있습니다 :

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로 입력을 올바르게 처리하거나 후행 줄 바꿈 양을 보존하는 방법을 모르겠습니다. 쉘은 바이너리 입력을 “사랑”하기 때문에 마지막 변형이 그대로 제공됩니다.

  1. read 백 슬래시를 해석합니다.
  2. read -r 백 슬래시를 해석하지 않지만 줄 바꿈으로 끝나지 않으면 마지막 줄을 삭제합니다.
  3. "$(…)"본 있기 때문에 I 종료되도록 다수의 후미로 바꿈 벗길 으로 ; echo -n a사용 echo -n "${line:0:-1}"이 지난 (캐릭터 상품이다 : a(더 포함한다)에 입력 없었다만큼 후미로 바꿈) 및 보존한다.

답변

시험 envsubst

FOO=foo
BAR=bar
export FOO BAR

envsubst <<EOF
FOO is $FOO
BAR is $BAR
EOF


답변

envsubst는 나에게 새로운 것이 었습니다. 환상적인.

레코드를 위해 heredoc을 사용하는 것이 conf 파일을 템플릿으로 만드는 좋은 방법입니다.

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


답변

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 항목이있는 템플릿을 처리합니다. 물론 템플릿 자체를 완전히 제어 할 수있는 경우 :

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

당신이 원하는 경우도 여기에 문서를 사용할 수 있습니다 catecho

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

@plockc는 bash quote escaping 문제를 피하는 솔루션을 제안했습니다.

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

편집 : sudo를 사용하여 루트로 이것을 실행하는 것에 대한 부분을 제거했습니다 …

편집 : 따옴표를 이스케이프 처리하는 방법에 대한 의견을 추가하고 믹스에 plockc의 솔루션을 추가했습니다!


답변

mogsie와 같은 bash 솔루션이 있지만 herestring 대신 heredoc을 사용하면 큰 따옴표를 피할 수 있습니다.

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


답변

2017 년 1 월 6 일 편집

구성 파일에 큰 따옴표를 유지해야했기 때문에 sed help로 큰 따옴표를 이스케이프 처리하면 다음과 같습니다.

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

Grégory Pakosz에 대한 모든 크레딧 .