답변:
세드 !
주어진 template.txt :
숫자는 $ {i}입니다 단어는 $ {word}입니다
우리는 다음과 같이 말해야합니다.
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
팁 -e
이 동일한 sed
호출에 여러 인수를 전달하는 Jonathan Leffler에게 감사합니다 .
cat
. 당신이 필요한 전부입니다 sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
.
sed
번거로운 이스케이프 텍스트가 필요합니다.
다음은 $ VAR 또는 $ {VAR}과 같은 변수를 대체하는 간단한 질문에 대한 yottatsa 의 솔루션 이며 간단한 한 줄짜리입니다.
i=32 word=foo envsubst < template.txt
물론 i 와 단어 가 당신의 환경에 있다면, 그것은 단지
envsubst < template.txt
내 Mac에서는 gettext의 일부로 MacGPG2 에서 설치된 것처럼 보입니다.
비슷한 질문에 대한 mogsie 솔루션의 개선 사항은 다음과 같습니다 . 내 솔루션에는 큰 따옴표를 escale 할 필요가 없으며 mogsie는하지만 하나는 라이너입니다!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
이 두 가지 솔루션의 장점은 일반적으로 $ ((...)),`...`및 $ (...)가 아닌 몇 가지 유형의 셸 확장 만 얻을 수 있다는 것 입니다 . 여기서 문자를 이스케이프 처리하지만 구문 분석에 버그가 있다는 것을 걱정할 필요는 없으며 여러 줄을 올바르게 수행합니다.
envsubst
envar을 내 보내지 않으면 베어 가 작동하지 않습니다.
envsubst
이름에서 알 수 있듯이 셸 변수가 아닌 환경 변수 만 인식 합니다 . 또한 가치는 주목할 것 A는 GNU의 유틸리티, 따라서 모든 플랫폼에 사전 설치 또는 사용할 수 없습니다. envsubst
사용하십시오 /bin/sh
. 변수를 설정하는 작은 쉘 스크립트를 작성한 다음 쉘 자체를 사용하여 템플리트를 구문 분석하십시오. 이와 같이 (개행을 올바르게 처리하도록 편집) :
the number is ${i}
the word is ${word}
#!/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"
#sh script.sh
the number is 1
the word is dog
bash
입력의 모든 명령이 실행됩니다. 템플릿이 "단어 : rm -rf $ HOME"인 경우 파일을 잃게됩니다.
read
작성된 명령은 각 줄에서 선행 및 후행 공백을 \
자르고 'eats' 문자를 자릅니다 . (c) 완전히 사용하는 경우에만 사용하십시오. 입력에 포함 된 명령 대체 ( `…`
또는 $(…)
)는의 사용으로 인해 임의의 명령을 실행할 수 있기 때문에 입력을 신뢰하거나 제어합니다 eval
. 마지막으로, echo
명령 행 옵션 중 하나의 행 시작 을 착각 할 가능성이 적습니다 .
최근 관심사를 감안할 때 이것에 대해 다시 생각하고 있었고 원래 생각했던 도구는 m4
autotools의 매크로 프로세서 라고 생각 합니다. 따라서 원래 지정한 변수 대신 다음을 사용합니다.
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubst
다른 답변에서 언급 했듯이이 간단한 변수 대체 / 템플릿 사용법에 사용합니다. m4
훌륭한 도구이지만 훨씬 더 많은 기능을 갖춘 본격적인 전 처리기이므로 일부 변수를 간단히 바꾸려는 경우에는 필요하지 않을 수도 있습니다.
template.txt
Variable 1 value: ${var1}
Variable 2 value: ${var2}
data.sh
#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"
parser.sh
#!/usr/bin/env bash
# args
declare file_data=$1
declare file_input=$2
declare file_output=$3
source $file_data
eval "echo \"$(< $file_input)\"" > $file_output
./parser.sh data.sh template.txt parsed_file.txt
parsed_file.txt
Variable 1 value: value 1
Variable 2 value: value 2
`…`
또는 $(…)
)는을 사용하여 임의의 명령을 실행하고을 사용 eval
하여 셸 코드를 직접 실행할 수 있으므로 입력 을 완전히 신뢰하거나 제어하는 경우에만 사용하십시오 source
. 또한 입력의 큰 따옴표는 조용히 삭제되므로 echo
명령 줄 옵션 중 하나로 줄의 시작 부분을 오인 할 수 있습니다.
여기의 강력한 배쉬 기능을 사용하면에도 불구하고 - 있음 eval
- 안전해야 사용이.
${varName}
입력 텍스트의 모든 변수 참조는 호출 쉘의 변수를 기반으로 확장됩니다.
다른 건 확장되지 않습니다 : 어느 변수 이름이되는 참조 하지 묶인 {...}
(예 $varName
)도 명령 대체 ( $(...)
레거시 구문 `...`
)이나 산술 대체 ( $((...))
레거시 구문 $[...]
).
를 $
리터럴로 취급하려면 \
이스케이프 처리하십시오. 예 :\${HOME}
입력은 stdin을 통해서만 허용됩니다 .
예:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
기능 소스 코드 :
expandVarsStrict(){
local line lineEscaped
while IFS= read -r line || [[ -n $line ]]; do # the `||` clause ensures that the last line is read even if it doesn't end with \n
# Escape ALL chars. that could trigger an expansion..
IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([$' '\1\2\3\4')
# ... then selectively reenable ${ references
lineEscaped=${lineEscaped//$'\4'{/\${}
# Finally, escape embedded double quotes to preserve them.
lineEscaped=${lineEscaped//\"/\\\"}
eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
done
}
함수에는없는 것으로 가정 0x1
, 0x2
, 0x3
및 0x4
그 때문에 문자 제어 문자 입력에 존재한다. 함수는 텍스트를 처리하기 때문에 내부적으로 사용되므로 안전한 가정이어야합니다.
eval
매우 안전합니다.
"
올바로 탈출 !)
${FOO:-bar}
하거나 설정된 경우에만 출력하는 것 ${HOME+Home is ${HOME}}
입니다. 나는 그것이 또한 변수를 누락 종료 코드를 반환 할 수있는 약간의 확장으로 생각 ${FOO?Foo is missing}
하지만, 현재 사용하지 않는 tldp.org/LDP/abs/html/parameter-substitution.html가 그 도움이된다면 이들의 목록을 가지고
작성 rendertemplate.sh
:
#!/usr/bin/env bash
eval "echo \"$(cat $1)\""
그리고 template.tmpl
:
Hello, ${WORLD}
Goodbye, ${CHEESE}
템플릿을 렌더링합니다 :
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
$(rm -rf ~)
코드로 실행중인 것입니다.
eval "echo \"$(cat $1)\""
잘 작동합니다!
다음은 이전 답변을 기반으로 한 펄을 사용한 솔루션이며 환경 변수를 대체합니다.
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
Perl 을 사용할 수 있다면 제 제안이 될 것입니다. 아마도 sed 및 / 또는 AWK 전문가가 아마도 훨씬 더 쉬운 방법을 알고있을 것입니다. 대체를 위해 dbName 이상으로 더 복잡한 맵핑이있는 경우이를 쉽게 확장 할 수 있지만이 시점에서 표준 Perl 스크립트에 넣을 수도 있습니다.
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
약간 더 복잡한 작업을 수행하는 짧은 Perl 스크립트 (여러 키 처리) :
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
위의 스크립트 이름을 replace-script로 지정하면 다음과 같이 사용할 수 있습니다.
replace-script < yourfile | mysql
다음은 파일의 내용이 큰 따옴표 사이에 입력 된 것처럼 쉘이 대체를 수행하도록하는 방법입니다.
내용과 함께 template.txt의 예를 사용하여 :
The number is ${i}
The word is ${word}
다음 줄은 셸이 template.txt의 내용을 보간하여 결과를 표준 출력에 씁니다.
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
설명:
i
그리고 word
실행 환경 변수로 전달됩니다 sh
.sh
전달 된 문자열의 내용을 실행합니다.echo "
'+ " $(cat template.txt)
"+ ' "
'"
" $(cat template.txt)
"의 출력이 cat template.txt
됩니다.sh -c
은 다음과 같습니다.
echo "The number is ${i}\nThe word is ${word}"
,i
및 word
지정된 환경 변수이다.'$(rm -rf ~)'$(rm -rf ~)
템플릿에 템플릿 파일의 리터럴 따옴표는 확장 전에 추가 한 따옴표와 일치합니다.
'$(echo a)'$(echo a)
. 생산합니다 'a'a
. 무슨 일이 일어나고 중요한 것은 처음이다 echo a
안쪽은 '
당신이에 이후 기대하지 않을 수있는 평가를지고 '
있지만, 포함과 같은 동작입니다 '
A의 "
인용 된 문자열.
"
인용 문자열 (을 포함하여 $(...)
)을 확장하는 것이 요점입니다.
${varname}
보안 위험이 높은 다른 확장을 요구하는 것만이 아닙니다 .
echo "
로 묶은 문자열과 따옴표가 붙은 큰 따옴표로 묶은 문자열 template.txt
, 그리고 다른 리터럴 문자열이 뒤에 오는 "
단일 인수로 연결된 따옴표로 묶 습니다 sh -c
. 당신은 '
일치 할 수없는 것이 맞습니다 (내부 쉘로 전달되지 않고 외부 쉘에서 소비 "
되었으므로). 그렇게 할 수 있으므로 템플릿을 포함하는 템플릿을 Gotcha"; rm -rf ~; echo "
실행할 수 있습니다.
file.tpl :
The following bash function should only replace ${var1} syntax and ignore
other shell special chars such as `backticks` or $var2 or "double quotes".
If I have missed anything - let me know.
script.sh :
template(){
# usage: template file.tpl
while read -r line ; do
line=${line//\"/\\\"}
line=${line//\`/\\\`}
line=${line//\$/\\\$}
line=${line//\\\${/\${}
eval "echo \"$line\"";
done < ${1}
}
var1="*replaced*"
var2="*not replaced*"
template file.tpl > result.txt
\$(date)
while IFS= read -r line; do
하는 것이 좋습니다 read
. 그렇지 않으면 각 입력 줄에서 앞뒤 공백을 제거합니다. 또한 echo
명령 줄 옵션 중 하나에 대한 줄 시작 부분을 오해 할 수 있으므로 사용하는 것이 좋습니다 printf '%s\n'
. 마지막으로 큰 따옴표를 사용하는 것이 더 안전합니다 ${1}
.
Sigil 과 같은 것을 사용하는 것이 좋습니다 : https://github.com/gliderlabs/sigil
단일 바이너리로 컴파일되므로 시스템에 설치하기가 매우 쉽습니다.
그런 다음 다음과 같은 간단한 단일 라이너를 수행 할 수 있습니다.
cat my-file.conf.template | sigil -p $(env) > my-file.conf
이것은 eval
정규식을 사용하는 것보다 훨씬 안전 하고 쉽습니다.sed
cat
사용 <my-file.conf.template
하는 것이 좋습니다 sigil
.FIFO 대신 실제 파일 핸들 을 제공 하십시오.
같은 것을 궁금해 하면서이 실을 발견했습니다. 그것은 나에게 영감을주었습니다 (백틱에주의하십시오)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
$(cat file)
입니다$(< file)
eval echo "\"$(cat FILE)\""
하지만 입력의 큰 따옴표는 버려지기 때문에 여전히 부족할 수 있습니다.
`…`
또는 $(…)
)는의 사용으로 인해 임의의 명령을 실행할 수 있으므로 입력 을 완전히 신뢰하거나 제어하는 경우에만 사용하십시오 eval
.
여기에 많은 선택이 있지만 힙에 내 것을 던질 것이라고 생각했습니다. 펄 기반이며 $ {...} 형식의 변수 만 대상으로하고 파일을 인수로 처리하여 stdout에서 변환 된 파일을 출력합니다.
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
물론 나는 실제로 펄 사람이 아니기 때문에 치명적인 결함이 쉽게 생길 수 있습니다 (그러나 나를 위해 작동합니다).
Env::import();
라인 가져 오기를 삭제할 수 use
있습니다. 또한 메모리에 전체 출력을 먼저 구성하지 않는 것이 좋습니다 . 루프 내부 print;
대신 대신 사용 $text .= $_;
하고 포스트 루프 print
명령을 삭제하십시오 .
구성 파일 형식을 제어 할 수있는 경우 bash 자체에서 수행 할 수 있습니다. 구성 파일을 서브 쉘이 아닌 소스 ( ".")로 지정하면됩니다. 그러면 변수가 서브 쉘 (서브 쉘이 종료 될 때 변수가 사라지는)이 아닌 현재 쉘의 컨텍스트에서 작성되고 계속 존재합니다.
$ cat config.data
export parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA
export parm_user=pax
export parm_pwd=never_you_mind
$ cat go.bash
. config.data
echo "JDBC string is " $parm_jdbc
echo "Username is " $parm_user
echo "Password is " $parm_pwd
$ bash go.bash
JDBC string is jdbc:db2://box7.co.uk:5000/INSTA
Username is pax
Password is never_you_mind
설정 파일이 쉘 스크립트가 될 수 없다면, 실행하기 전에 '컴파일'하면됩니다 (컴파일은 입력 형식에 따라 다릅니다).
$ cat config.data
parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA # JDBC URL
parm_user=pax # user name
parm_pwd=never_you_mind # password
$ cat go.bash
cat config.data
| sed 's/#.*$//'
| sed 's/[ \t]*$//'
| sed 's/^[ \t]*//'
| grep -v '^$'
| sed 's/^/export '
>config.data-compiled
. config.data-compiled
echo "JDBC string is " $parm_jdbc
echo "Username is " $parm_user
echo "Password is " $parm_pwd
$ bash go.bash
JDBC string is jdbc:db2://box7.co.uk:5000/INSTA
Username is pax
Password is never_you_mind
특정 경우에는 다음과 같은 것을 사용할 수 있습니다.
$ cat config.data
export p_p1=val1
export p_p2=val2
$ cat go.bash
. ./config.data
echo "select * from dbtable where p1 = '$p_p1' and p2 like '$p_p2%' order by p1"
$ bash go.bash
select * from dbtable where p1 = 'val1' and p2 like 'val2%' order by p1
그런 다음 go.bash의 출력을 MySQL과 voila로 파이프하면 데이터베이스를 손상시키지 않기를 바랍니다 :-).
go.bash
스틱의 끝이 잘못되었습니다. 이것은 솔루션의 일부가 아니며 변수가 있다는 것을 보여주는 방법 일뿐입니다 올바르게 설정하십시오.
제한된 현재 사용 사례에서 작동하지만 더 복잡한 상황에서는 충분하지 않기 때문에 현재 제안보다 더 강력한 것을 원할 것입니다.
더 나은 렌더러가 필요합니다. 최고의 렌더러가 필요합니다. 당신은 Renderest가 필요합니다!
주어진 template.txt :
안녕하세요, {{person}}!
운영:
$ person = Bob ./render template.txt
그리고 당신은 출력을 볼 수 있습니다
안녕 밥!
stdout을 파일로 리디렉션하여 파일에 씁니다.
$ person = Bob ./render template.txt> rendered.txt
그리고 보간하고 싶지 않은 $ {} 변수가있는 스크립트를 렌더링하는 경우 다른 작업을 수행하지 않고도 Renderest를 사용할 수 있습니다!
https://github.com/relaxdiego/renderest 에서 계속해서 사본을 받으십시오.