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

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

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

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

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

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

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

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

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

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

종류 안부



답변

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

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

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

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


답변

답변 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'각각.


답변

이 주제가 오래되었다는 것을 알고 있지만 변수를 내 보내지 않고도 더 간단한 작업 솔루션이 있습니다. 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}대체해서는 안되는 입력 파일을 상상해보십시오 .


답변

  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

“축하합니다”가 표시됩니다.


답변

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

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


답변

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

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

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

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


답변

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

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

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