bash가 파일에서로드 된 문자열에서 변수를 확장하도록 강제
bash (강제?) 문자열 (파일에서로드 된) 확장 변수를 만드는 방법을 알아 내려고 노력 중입니다.
내용이 포함 된 "something.txt"라는 파일이 있습니다.
hello $FOO world
그런 다음 실행
export FOO=42
echo $(cat something.txt)
이것은 다음을 반환합니다.
hello $FOO world
변수가 설정되어 있어도 $ FOO를 확장하지 않았습니다. 파일을 평가하거나 소싱 할 수 없습니다. 파일을 시도하고 실행할 수 있기 때문입니다 (그대로 실행 가능하지 않습니다. 변수가 삽입 된 문자열을 원합니다).
어떤 아이디어?
나는이 질문에 대한 답이 바로 envsubst
명령 이라고 생각하는 것을 우연히 발견했습니다 .
envsubst < something.txt
배포판에서 아직 사용할 수없는 경우
GNU 패키지 gettext
.
@Rockallite- '\ $'문제를 처리하기 위해 작은 래퍼 스크립트를 작성했습니다.
(BTW, 입력의 일부 변수 만 확장하기 위해 https://unix.stackexchange.com/a/294400/7088 에 설명 된 envsubst의 "기능"이 있지만 예외를 이스케이프하는 것이 훨씬 더 많다는 데 동의합니다. 편리한.)
내 스크립트는 다음과 같습니다.
#! /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 "$@"
많은 답변 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
변수를 설정하는 쉘 스크립트 인 a와 template.txt
해당 변수를 사용하는 템플릿 인 a 와 함께 다음과 같이 사용할 수 있습니다 .
. parameters.cfg
printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt
실제로 저는 이것을 일종의 경량 템플릿 시스템으로 사용합니다.
당신은 시도 할 수 있습니다
echo $(eval echo $(cat something.txt))
각 줄을 인쇄하지 않고 평가 하고 싶습니다. Bash가 변수 대체를 수행 할 수 있도록 하고 .
FOO=42
while read; do
eval echo "$REPLY"
done < something.txt
보다 help eval
또는 Bash 설명서를 참조하십시오.
또 다른 접근 방식 (이상해 보이지만 어쨌든 여기에 넣습니다) :
echo 문을 감싸고 something.txt의 내용을 임시 파일에 씁니다.
something=$(cat something.txt)
echo "echo \"" > temp.out
echo "$something" >> temp.out
echo "\"" >> temp.out
그런 다음 다시 변수로 소싱하십시오.
RESULT=$(source temp.out)
$ RESULT는 모두 확장됩니다. 그러나 그것은 너무 잘못된 것 같습니다!
변수 참조 만 확장하려면 (내가 갖고있는 목표) 아래를 수행 할 수 있습니다.
contents="$(cat something.txt)"
echo $(eval echo \"$contents\")
($ contents 주위의 이스케이프 된 따옴표가 여기에서 핵심입니다)
bash
방법, ( Michael Neale의 대답 의 한 줄 변형 ), 프로세스 및 명령 대체 사용 :FOO=42 . <(echo -e echo $(<something.txt))
산출:
hello 42 world
참고
export
필요하지 않습니다.something.txt 에 여러 줄이있는 경우 GNU 평가 방법 :
sed
e
FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
$ 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.
foo=45
file=something.txt # in a file is written: Hello $foo world!
eval echo $(cat $file)
다음 솔루션 :
정의 된 변수를 대체 할 수 있습니다.
정의되지 않은 변경되지 않은 변수 자리 표시자를 남깁니다. 이것은 자동화 된 배포 중에 특히 유용합니다.
다음 형식의 변수 대체를 지원합니다.
${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
envsubst
is a great solution (see LenW's answer) if the content you're substituting is of "reasonable" length.
In my case, I needed to substitute in a file's content to replace the variable name. envsubst
requires that the content be exported as environment variables and bash has a problem when exporting environment variables that are more than a megabyte or so.
awk solution
Using cuonglm's solution from a different question:
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
This solution works for even large files.
The following works: bash -c "echo \"$(cat something.txt)"\"
'Program Tip' 카테고리의 다른 글
간단한 문자열 배열에 바인딩 (0) | 2020.11.07 |
---|---|
jQuery의 부모에서 모든 자식 (모든 수준)을 선택하는 방법은 무엇입니까? (0) | 2020.11.07 |
"mailto :"또는 "tel :"과 같은 skype에 대한 href 속성이 있습니까? (0) | 2020.11.07 |
트위터 부트 스트랩 드롭 다운 토글 링크를 클릭하도록 허용 하시겠습니까? (0) | 2020.11.07 |
주어진 사용자의 모든 프로세스를 종료합니다. (0) | 2020.11.07 |