[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"
두 가지 모두에 동일한 파일을 사용하려면 sponge
Johnny 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
(만 VAR1
과 VAR2
의) 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}
대체해서는 안되는 입력 파일을 상상해보십시오 .
답변
- ENV 변수 정의
$ export MY_ENV_VAR=congratulation
- 다음 내용으로 템플릿 파일 ( in.txt ) 만들기
$MY_ENV_VAR
(리눅스에서) $ TERM, $ SHELL, $ HOME …과 같이 시스템에서 정의한 다른 모든 ENV 변수를 사용할 수도 있습니다.
- 이 명령을 실행하여 in.txt 파일의 모든 환경 변수를 raplace 하고 결과를 out.txt에 씁니다.
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
- out.txt 파일 내용 확인
$ cat out.txt
“축하합니다”가 표시됩니다.
답변
정말로 bash (및 sed)를 사용하고 싶다면 각 환경 변수 ( set
posix 모드에서 반환 됨 )를 살펴보고 -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 변수가 실제 값으로 바뀝니다. 인용문도 보존됩니다. 🙂