배시 템플릿:Bash를 사용하여 템플릿에서 구성 파일을 작성하는 방법
Apache 및 PHP용 구성 파일 생성을 자동화하는 스크립트를 작성하고 있습니다.CPanel이나 ISPConfig 등의 GUI는 사용하고 싶지 않습니다.
Apache 및 PHP 구성 파일 템플릿이 있습니다.Bash 스크립트는 템플릿을 읽고 변수를 대체하며 구문 분석된 템플릿을 일부 폴더에 출력해야 합니다.그것을 하는 가장 좋은 방법은?몇 가지 방법을 생각할 수 있습니다.어떤 것이 가장 좋습니까, 아니면 더 나은 방법이 있을까요?순수한 Bash로 하고 싶다(예를 들어 PHP에서는 쉽다)
템플릿입니다.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"
그런데 여기서 출력을 외부 파일로 리다이렉트하려면 어떻게 해야 하나요?변수에 따옴표가 포함되어 있는 경우, 뭔가 이스케이프할 필요가 있습니까?
- 각 변수를 값으로 대체하기 위해 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" 바이너리 입력이기 때문에 그대로 표시됩니다.
read
을 사용하다read -r
는 백슬래시를 해석하지 않지만 새 행으로 끝나지 않으면 마지막 행을 드롭합니다."$(…)"
행이 합니다.…
; 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
논의
- 괄호는 하위 셸을 열며, 생성된 모든 출력을 그룹화하는 것을 목적으로 합니다.
- 서브셸 내에서 모든 변수 선언을 생성합니다.
- 에서는 「」를 합니다.
cat
GREENDOC - 마지막으로 서브셸 출력을 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
(최종마감(폐쇄)}
합니다 기능을 정지합니다.
- 것이 BREAK입니다).
- 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
'programing' 카테고리의 다른 글
SQL Server 데이터베이스 버전 제어 방법 (0) | 2023.04.19 |
---|---|
WPF에서 UI(메인) 스레드에 안전하게 액세스 (0) | 2023.04.19 |
Bash 스크립트가 병렬로 제한된 수의 명령을 처리합니다. (0) | 2023.04.19 |
+ 또는 -로 시작하는 필드에서는 Excel csv 수식 변환을 바이패스합니다. (0) | 2023.04.19 |
xlsm 또는 xlsb 형식은 언제 사용해야 합니까? (0) | 2023.04.19 |