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 줄 = "$ (고양이; 에코 -na)" end_offset = $ {# line} [[ "$ {line : 0 : $ end_offset}"= ~ (. *) (\ $ \ {([a-zA-Z _] [a-zA-Z_0-9] *) \}) (. * )]]; 하다 PRE = "$ {BASH_REMATCH [1]}" POST = "$ {BASH_REMATCH [4]} $ {line : $ end_offset : $ {# line}}" VARNAME = "$ {BASH_REMATCH [3]}" 평가 'VARVAL = "$'$ VARNAME '"' 줄 = "$ PRE $ VARVAL $ POST" end_offset = $ {# PRE} 끝난 echo -n "$ {line : 0 : -1}"
경고 : bash에서 NUL로 입력을 처리하거나 후행 줄 바꿈 양을 보존하는 방법을 모르겠습니다. 쉘은 바이너리 입력을 "사랑"하기 때문에 마지막 변형이 그대로 제공됩니다.
read
백 슬래시를 해석합니다.read -r
백 슬래시를 해석하지 않지만 줄 바꿈으로 끝나지 마지막 줄을 삭제합니다."$(…)"
본 있기 때문에 나는되도록 다수의 종료 후미로 바꿈 벗길…
으로; 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
됩니다.
이 원하는 경우 당신도 계명 여기에 문서를 사용할 수 있습니다 cat
에echo
$ eval "cat <<< \"$(<template.txt)\"" 2> /dev/null
@plockc는 bash quote escaping 문제를 피하는 솔루션을 제안했습니다.
$ eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
편집 : sudo를 사용하여 루트로 실행하는 것에 대한 부분을 제거했습니다 ...
편집 : 따옴표를 이스케이프 처리하는 방법에 대한 의견을 추가하고 믹스에 plockc의 솔루션을 추가했습니다!
mogsie와 같은 bash 솔루션이 사용하면 여기에 큰 따옴표를 피할 수 있습니다.
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에 대한 모든 .
허용되는 답변의 길지만 강력한 버전 :
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
또는 ${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
나는이 방법을 사용했을 것입니다. 아마 덜 덜이지만 읽기 / 유지 관리하기 어렵습니다.
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 파일 및 입력 스트림의 템플릿
- 환경 변수에서 템플릿
envsubst로 바퀴를 재발 명하는 대신거의 모든 시나리오에서 사용할 수 있습니다 (예 : 도커 컨테이너의 환경 변수에서 구성 파일 작성).
Mac에서 homebrew 가 있는지 확인 하고 gettext에서 연결하십시오.
brew install gettext
brew link --force gettext
./template.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.sh
#!/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
순수한 bash를 사용하여 ZyX에서 답을 얻었습니다 새로운 스타일의 정규 일치 및 간접 변수 대체로
#!/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. Bentley의 강력한 대답을 고려하십시오 .
이 답변의 목표는 제공하는 bash는 전용 솔루션 의 사용에도 불구하고-그렇게 eval
해야- 사용하는 것이 안전합니다 .
목표는 다음과 가변적
- 가변 참조
${name}
및$name
가변 참조의 확장을 지원합니다 . - 다른 모든 확장을 방지하십시오.
- 명령 대체 (
$(...)
및 레거시 구문`...`
) - 산술 대체 (
$((...))
및 레거시 구문$[...]
).
- 명령 대체 (
- 접두사
\
( ) 로 변수 확장을 선택적으로 선택할 수 있습니다.\${name}
- 특수 문자를 유지하십시오. 입력에서 현저
"
하고\
인스턴스. - 인수 또는 stdin을 입력을 허용하십시오.
기능expandVars()
:
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
- 성능상의 MIST이 함수는 stdin 입력 을 한 번 에 메모리로 읽지 만 함수를 한 줄씩 접근하는 것이지만 함수입니다.
- 또한 내장 명령이나 산술 대체가 포함되어 있지 않은 경우 와 같은 비 기본 변수 확장 도 지원합니다.
${HOME:0:10}
${HOME:0:$(echo 10)}
- (모두
$(
및`
인스턴스가 맹목적으로 이스케이프되기 ) - 많은
${HOME
(닫기 누락}
) BREAK 함수 와 같은 잘못된 변수 참조
- (모두
- bash가 큰 따옴표로 묶은 페이지를 처리하기 백 슬래시는 다음과 같이 처리됩니다.
\$name
확장을 방지합니다.\
오는 뒤 6 하나$
는 그대로 유지됩니다.- 여러 인접한
\
인스턴스 를 나타내 려면 두 배로 늘려야합니다 . 예 :\\
->\
-그대로\
\\\\
->\\
- 내부 목적으로 사용되는 다음을 포함 할 수 없습니다 입력 (거의 사용하지 않음) 문자 :
0x1
,0x2
,0x3
.
- bash가 새로운 확장 구문을 도입해야한다면이 함수가 제안 확장을 막지 가능성이 있습니다
eval
. 사용하지 않는 솔루션에 아래를 참조하십시오 .
확장 만 지원 하는 보다 제한적인 솔루션을${name}
찾고 있다면 ( 즉, 필수 중괄호, $name
참조 무시) 이 답변 을 참조하십시오 .
허용 된 답변 의 bash 전용 eval
무료 솔루션의 강화 버전은 다음과 가변 .
개선 사항은 다음과 가능합니다.
- 가변 참조
${name}
및$name
가변 참조의 확장을 지원합니다 . \
확장 안되는 -escaping 변수 참조를 지원합니다 .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"
또 다른 순수한 bash 솔루션이 있습니다.
- heredoc을 사용하고 있으므로 다음을 수행하십시오.
- 추가로 필요한 구문으로 인해 기초가 증가하지 않습니다.
- 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
HEREDOC로 명령을 생성합니다. - 마지막으로 서브 쉘 출력을 bash에 공급하고 원하는 출력을 생성합니다.
이 출력을 파일로 리디렉션하려면 마지막 줄을 다음으로 바꿉니다.
) | bash > output.txt
awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < input.txt > output.txt
shtpl을 위한 완벽한 케이스 . (내 프로젝트이므로 널리 사용되지 않고 문서가 부족합니다. 그러나 여기에 그것이 제공하는 솔루션이 있습니다. 테스트 해보고 싶을 수도 있습니다.)
다음을 실행하십시오.
$ i=1 word=dog sh -c "$( shtpl template.txt )"
결과는 다음과 같습니다.
the number is 1
the word is dog
즐기세요.
# 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
다음은 공백을 유지하는 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 envar가없는 경우 $ {VAR}를 빈 문자열로 바꿉니다.
- 이름에서 az, AZ, 0-9 및 밑줄 문자 만 지원합니다 (첫 번째 위치의 숫자 제외).
여기에서 간단한 변수 대체 파이썬 스크립트를보십시오 : https://github.com/jeckep/vsubst
사용이 매우 간단합니다.
python subst.py --props secure.properties --src_path ./templates --dst_path ./dist
'IT' 카테고리의 다른 글
Ruby 객체가 부울인지 확인하는 방법 (0) | 2020.07.21 |
---|---|
변수를 2로 나눌 수 있는지 확인 (0) | 2020.07.21 |
URL을 공유로 변환 한 후 다시 변환 (0) | 2020.07.21 |
Java에서 시간 소인을 밀리 초 단위의 클래스 형식 시간으로 변환 (0) | 2020.07.21 |
C에서 % n 형식 지정 튼 사용하는 것은 무엇입니까? (0) | 2020.07.21 |