복잡한 텍스트 파일에서 쉘 변수를 대체하는 방법


84

쉘 변수 (예 : $ VAR1 또는 $ VAR2)를 도입 한 여러 텍스트 파일이 있습니다.

해당 파일 (하나씩)을 가져 와서 모든 변수가 교체 된 새 파일에 저장하고 싶습니다.

이를 위해 다음 셸 스크립트 (StackOverflow에 있음)를 사용했습니다.

while read line
do
    eval echo "$line" >> destination.txt
done < "source.txt"

이것은 매우 기본적인 파일에서 매우 잘 작동합니다.

그러나 더 복잡한 파일에서는 "eval"명령이 너무 많은 작업을 수행합니다.

  • "#"로 시작하는 줄은 건너 뜁니다.

  • XML 파일 구문 분석으로 인해 많은 오류가 발생합니다.

더 나은 방법이 있습니까? (쉘 스크립트에서 ... 예를 들어 Ant로 쉽게 수행된다는 것을 알고 있습니다)

종류 안부

답변:


196

내 시스템 envsubst에 gettext-base 패키지의 일부인 명령이 있습니다.

따라서 다음과 같이 쉽게 할 수 있습니다.

envsubst < "source.txt" > "destination.txt"

두 가지 모두에 동일한 파일을 사용하려면 spongeJohnny Utahh가 제안한대로 moreutil 's 와 같은 것을 사용해야 envsubst < "source.txt" | sponge "source.txt"합니다. (그렇지 않으면 셸 리디렉션이 파일을 읽기 전에 비우기 때문입니다.)


4
큰! 그러나 환경 변수에 대해서만 작동합니다. 내 .sh 스크립트에 선언 된 변수로 어떻게 작동시킬 수 있습니까?
Ben

10
@ 벤 : 사용 '수출'당신이 envsubst에 사용할 모든 변수 (envsubst 호출하기 전에)
TLO

7
envsubst의 일부 GNU gettext에
앤디

3
@user_mda 출력이 표시됩니다.
derobert

4
경고 : 변수 확장 외부의 문자 가 source.txt포함 된 경우이 $문자 envsubst도 대체되며 $. 일반적인 (추악한) 해결 방법은 export DOLLAR="$".
Kos

60

답변 2와 관련하여 envsubst에 대해 논의 할 때 다음과 같이 질문했습니다.

내 .sh 스크립트에 선언 된 변수로 어떻게 작동하도록 할 수 있습니까?

대답은를 호출하기 전에 변수를 내보내기 만하면된다는 것 envsubst입니다.

envsubst SHELL_FORMAT인수를 사용하여 입력에서 대체하려는 변수 문자열을 제한 할 수도 있습니다 (예 : 공통 쉘 변수 값으로 입력에서 문자열이 의도하지 않게 대체되는 것을 방지 함 $HOME).

예를 들면 :

export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'

envsubst "$MYVARS" <source.txt >destination.txt

모든 인스턴스의 대체합니다 $VAR1$VAR2(만 VAR1VAR2의) source.txt'somevalue''someothervalue'각각.


14
단일 따옴표 '세트에 사용되는 MYVARS매우 중요하다
마크 Lakata

그 주 export, envsubst또는 텍스트 - 투 - 대체가 큰 경우 어떤 인터리빙 명령이 실패 할 수 있습니다. 참고.
비숍

@ram SHELL_FORMAT인수를 생략하면 (예 :) "$MYVARS"내 보낸 모든 변수가 대체되기 때문입니다. 그것이 당신에게 필요한 것이라면 걱정할 필요가 없습니다.
Thiago Figueiro

12

이 주제가 오래되었다는 것을 알고 있지만 변수를 내 보내지 않고도 더 간단한 작업 솔루션이 있습니다. oneliner가 될 수 있지만 \온라인 끝을 사용하여 분할하는 것을 선호합니다 .

var1='myVar1'\
var2=2\
var3=${var1}\
envsubst '$var1,$var3' < "source.txt" > "destination.txt"

#         ^^^^^^^^^^^    ^^^^^^^^^^     ^^^^^^^^^^^^^^^
# define which to replace   input            output

변수 envsubst는 환경 변수로 간주되기 위해 동일한 행에 정의되어야합니다 .

'$var1,$var3'오직 지정된 사람을 대체 할 선택 사항입니다. ${VARIABLE_USED_BY_JENKINS}대체해서는 안되는 입력 파일을 상상해보십시오 .


8
  1. ENV 변수 정의
$ export MY_ENV_VAR=congratulation
  1. 다음 내용으로 템플릿 파일 ( in.txt ) 만들기
$MY_ENV_VAR

(리눅스에서) $ TERM, $ SHELL, $ HOME ...과 같이 시스템에서 정의한 다른 모든 ENV 변수를 사용할 수도 있습니다.

  1. 이 명령을 실행하여 in.txt 파일의 모든 환경 변수를 raplace 하고 결과를 out.txt에 씁니다.
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
  1. out.txt 파일 내용 확인
$ cat out.txt

"축하합니다"가 표시됩니다.


0

정말로 bash (및 sed)를 사용하고 싶다면 각 환경 변수 ( setposix 모드에서 반환 됨 )를 살펴보고 -e 'regex'sed로 끝나는 sed 묶음을 빌드 한 -e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g'다음 모든 것을 전달합니다. sed.

Perl은 더 좋은 일을 할 수 있지만 환경 변수에 배열로 액세스 할 수 있으며 실행 가능한 대체를 수행 할 수 있으므로 환경 변수를 한 번만 일치시킬 수 있습니다.


왜 누군가가 이런 대답을 반대표를 던 졌는지 ??? -perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' "$main_tf_file"
Yordan 게오르기

0

실제로 백 슬래시를 무시 하도록 변경해야 read합니다 read -r.

또한 따옴표와 백 슬래시를 이스케이프해야합니다. 그래서

while read -r line; do
  line="${line//\\/\\\\}"
  line="${line//\"/\\\"}"
  line="${line//\`/\\\`}"
  eval echo "\"$line\""
done > destination.txt < source.txt

그래도 확장을 수행하는 끔찍한 방법입니다.


사실, 그것은 나쁜 코드를 포함 할 수있는 파일에 대해 "eval"을 할 때의 위험입니다
Ben

0

필요한 모든 변수를 내 보낸 다음 perl onliner를 사용하십시오.

TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')

그러면 TEXT에있는 모든 ENV 변수가 실제 값으로 바뀝니다. 인용문도 보존됩니다. :)


0

env가 아닌 모든 변수를 그대로 유지하면서 소스 파일에서 env 변수를 대체하려면 다음 명령을 사용할 수 있습니다.

envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txt

여기 에서는 특정 변수 만 바꾸는 구문에 대해 설명합니다 . 위의 명령은 하위 쉘을 사용하여 정의 된 모든 변수를 나열한 다음envsubst

따라서라는 정의 된 env 변수가 $NAME있고 source.txt파일이 다음과 같은 경우 :

Hello $NAME
Your balance is 123 ($USD)

다음과 destination.txt같습니다.

Hello Arik
Your balance is 123 ($USD)

(가) 통지 $NAME를 교체하고이 $USD그대로 남아


0

내 보낸 변수 이름을 키로 포함하고 내 보낸 변수 값을 다음과 같이 포함하는 특수 해시 의 키를 반복하는 작은 따옴표로 -piperl 코드 (the -e)를 실행하여 검색 및 라인 별 모드 (the ) 에서 perl 바이너리를 호출합니다. %ENV키의 값과 각 반복에 대해 a $<<key>>를 포함하는 문자열을 <<value>>.

 perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' file

주의 사항 : 둘 이상의 변수가 동일한 문자열로 시작하는 경우 추가 논리 처리가 필요합니다.


-1

envsubst내가 사용하고 싶은 것과 똑같은 것 같지만 -v옵션은 나를 약간 놀랐습니다.

envsubst < template.txt잘 작동 하는 동안 옵션 -v이 작동하지 않았습니다.

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)
$ envsubst -V
envsubst (GNU gettext-runtime) 0.18.2
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

내가 썼 듯이 이것은 작동하지 않았습니다.

$ envsubst -v < template.txt
envsubst: missing arguments
$ cat template.txt | envsubst -v
envsubst: missing arguments

나는 그것을 작동시키기 위해 이것을해야했다.

TEXT=`cat template.txt`; envsubst -v "$TEXT"

누군가에게 도움이 될 수도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.