bash를 강제로 파일에서 로드된 문자열의 변수 확장
저는 bash(force?)를 만드는 방법을 생각하고 있습니다.파일에서 로드된 문자열의 변수를 확장합니다.
"something.txt"라는 파일이 있는데 내용은 다음과 같습니다.
hello $FOO world
나는 그 다음에 달립니다.
export FOO=42
echo $(cat something.txt)
다음과 같이 반환됩니다.
hello $FOO world
변수를 설정했는데도 $FOO를 확장하지 않았습니다.파일을 평가하거나 소스화할 수 없습니다. 파일을 실행하려고 하기 때문입니다(있는 그대로 실행할 수 없습니다. 변수가 삽입된 문자열을 원합니다).
아이디어 있어요?
저는 이 질문에 대한 답이라고 생각하는 것을 우연히 발견했습니다.envsubst
명령:
echo "hello \$FOO world" > source.txt
export FOO=42
envsubst < source.txt
다음 출력은 다음과 같습니다.hello 42 world
파일의 데이터에 대한 작업을 계속하려면 다음과 같이 하십시오.destination.txt
이 파일을 다음과 같은 파일로 다시 밀어넣기:
envsubst < source.txt > destination.txt
당신의 디스트리뷰터에서 아직 사용할 수 없는 경우, GNU 패키지에 있습니다.gettext
.
@로컬라이트
- 저는 $' 문제를 해결하기 위해 작은 포장지 스크립트를 작성했습니다.
(BTW, envsubst의 "기능"은 https://unix.stackexchange.com/a/294400/7088 에서 입력의 일부 변수만 확장하는 것에 대해 설명했지만, 저는 예외를 피하는 것이 훨씬 더 편리하다는 것에 동의합니다.)
내 대본은 다음과 같습니다.
#! /bin/bash
## -*-Shell-Script-*-
CmdName=${0##*/}
Usage="usage: $CmdName runs envsubst, but allows '\$' to keep variables from
being expanded.
With option -sl '\$' keeps the back-slash.
Default is to replace '\$' with '$'
"
if [[ $1 = -h ]] ;then echo -e >&2 "$Usage" ; exit 1 ;fi
if [[ $1 = -sl ]] ;then sl='\' ; shift ;fi
sed 's/\\\$/\${EnVsUbDolR}/g' | EnVsUbDolR=$sl\$ envsubst "$@"
해볼 수 있습니다
echo $(eval echo $(cat something.txt))
많은 답변은 다음을 사용합니다.eval
그리고.echo
작업의 종류이지만 여러 줄에 대한 중단, 셸 메타 변환기 탈출 시도, bash에 의해 확장되지 않은 템플릿 내부 탈출 등과 같은 다양한 작업.
저도 같은 문제가 있었고, 제가 아는 한 모든 것을 올바르게 처리하는 셸 함수를 작성했습니다.bash의 명령 대체 규칙 때문에 템플릿에서 줄바꿈만 제거되지만, 다른 모든 것이 그대로 유지되는 한 문제가 되는 것을 발견한 적이 없습니다.
apply_shell_expansion() {
declare file="$1"
declare data=$(< "$file")
declare delimiter="__apply_shell_expansion_delimiter__"
declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
eval "$command"
}
예를 들어, 다음과 같이 사용할 수 있습니다.parameters.cfg
그것은 정말로 변수를 설정하는 셸 스크립트이고, 그리고.template.txt
이는 다음과 같은 변수를 사용하는 것입니다.
. parameters.cfg
printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt
실제로, 저는 이것을 일종의 경량 템플릿 시스템으로 사용합니다.
각 행을 인쇄하는 것이 아니라 Bash가 변수 대체를 수행할 수 있도록 평가하는 것입니다.
FOO=42
while read; do
eval echo "$REPLY"
done < something.txt
봐help eval
자세한 내용은 Bash 설명서를 참조하십시오.
또 다른 접근 방식(어색해 보이지만 어쨌든 여기에 넣겠습니다):
어떤 것의 내용을 쓰시오.txt는 에코 문이 있는 임시 파일로 둘러싸여 있습니다.
something=$(cat something.txt)
echo "echo \"" > temp.out
echo "$something" >> temp.out
echo "\"" >> temp.out
그런 다음 다시 변수에 소스를 넣습니다.
RESULT=$(source temp.out)
$RESULT는 모든 것을 확장할 것입니다.하지만 너무 잘못된 것 같아요!
임시 파일이 필요 없는 한 줄 솔루션:
RESULT=$(source <(echo "echo \"$(cat something.txt)\""))
#or
RESULT=$(source <(echo "echo \"$(<something.txt)\""))
변수 참조만 확장하기를 원한다면(나 자신을 위한 목표) 아래와 같이 할 수 있습니다.
contents="$(cat something.txt)"
echo $(eval echo \"$contents\")
($contents 주변의 이스케이프된 인용문이 핵심입니다.)
뭔가.txt는 한 줄만 가지고 있습니다, a
bash
프로세스 및 명령 대체를 사용하는 방법(Michael Neale의 "icky" 답변의 짧은 버전):FOO=42 . <(echo -e echo $(<something.txt))
출력:
hello 42 world
:
export
필요하지 않습니다.뭔가.txt에는 하나 이상의 줄, GNU가 있습니다.
sed
e
평가 방법:FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
다음 솔루션:
정의된 변수를 대체할 수 있습니다.
정의되지 않은 변수 자리 표시자를 변경하지 않습니다.이 기능은 자동 배포 시 특히 유용합니다.
에서는 다음과 같은 형식으로 변수를 대체할 수 있습니다.
${var_NAME}
$var_NAME
환경에 정의되지 않은 변수를 보고하고 이러한 경우에 대한 오류 코드를 반환합니다.
TARGET_FILE=someFile.txt;
ERR_CNT=0;
for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do
VAR_VALUE=${!VARNAME};
VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' );
VAR_VALUE2=${!VARNAME2};
if [ "xxx" = "xxx$VAR_VALUE2" ]; then
echo "$VARNAME is undefined ";
ERR_CNT=$((ERR_CNT+1));
else
echo "replacing $VARNAME with $VAR_VALUE2" ;
sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE};
fi
done
if [ ${ERR_CNT} -gt 0 ]; then
echo "Found $ERR_CNT undefined environment variables";
exit 1
fi
foo=45
file=something.txt # in a file is written: Hello $foo world!
eval echo $(cat $file)
$ eval echo $(cat something.txt)
hello 42 world
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.
envsubst
대체하고 있는 콘텐츠가 "합리적"인 길이의 콘텐츠인 경우에는 훌륭한 솔루션입니다(LenW의 답변 참조).
제 경우, 변수 이름을 대체하기 위해 파일의 내용을 대체해야 했습니다. envsubst
에서는 컨텐츠를 환경 변수로 내보내야 하며, 1MB 이상의 환경 변수를 내보낼 때 bash에 문제가 있습니다.
어색한 해결책
다른 질문에서 cuonglm의 솔루션 사용:
needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.)
needle_file="doc1_base64.txt" # Will be substituted for the needle
haystack=$requestfile1 # File containing the needle
out=$requestfile2
awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out
이 솔루션은 대용량 파일에서도 사용할 수 있습니다.
expenv () {
LF=$'\n'
echo "cat <<END_OF_TEXT${LF}$(< "$1")${LF}END_OF_TEXT" | bash
return $?
}
expenv "file name"
작품들: 다음작업가능성이::bash -c "echo \"$(cat something.txt)"\"
언급URL : https://stackoverflow.com/questions/10683349/forcing-bash-to-expand-variables-in-a-string-loaded-from-a-file
'programing' 카테고리의 다른 글
깃 저장소를 특정 커밋으로 롤백하려면 어떻게 해야 합니까? (0) | 2023.05.28 |
---|---|
Objective-C에서 NSRay를 NSString으로 변환 (0) | 2023.05.28 |
C#에서 두 개 이상의 바이트 배열을 결합하는 가장 좋은 방법 (0) | 2023.05.23 |
쿼리 계획에서 "비트맵 힙 검사"란 무엇입니까? (0) | 2023.05.23 |
Collections.defaultdict 차이와 일반 dict (0) | 2023.05.23 |