셸 스크립트에 구성 파일 사용

내 스크립트에 대한 구성 파일을 만들어야합니다.
예는 다음과 같습니다.

스크립트 :

#!/bin/bash source /home/myuser/test/config echo "Name=$nam" >&2 echo "Surname=$sur" >&2 

/home/myuser/test/config의 콘텐츠 :

nam="Mark" sur="Brown" 

작동합니다!

내 질문 : 이 올바른 방법입니다. 아니면 다른 방법이 있습니까?

댓글

  • 변수가 맨 위에 있어야합니다. I ‘ 작동하는 것에 놀랐습니다. 어쨌든 구성 파일이 필요한 이유는 무엇입니까?이 변수를 다른 곳에서 사용할 계획입니까?
  • 제 스크립트에는 많은 옵션이 있으므로 변수가 필요합니다. config 파일이 스크립트를 형식화합니다. 감사합니다.
  • IMHO 괜찮습니다.이 방법을 사용하겠습니다.
  • abcde도이 방법을 사용합니다. (쉘 스크립트의 경우) 상당히 큰 프로그램입니다. 여기 에서 볼 수 있습니다.

Answer

source는 임의의 코드를 실행하므로 안전하지 않습니다. 이것은 당신에게 문제가되지 않을 수 있지만, 파일 권한이 잘못된 경우 파일 시스템 액세스 권한이있는 공격자가 다음과 같이 다른 보안 스크립트에 의해로드 된 구성 파일에 코드를 삽입하여 권한이있는 사용자로 코드를 실행할 수 있습니다. init 스크립트.

지금까지 제가 확인할 수 있었던 최고의 솔루션은 서투른 재창조 솔루션입니다.

myscript.conf

password=bar echo rm -rf / PROMPT_COMMAND="echo "Sending your last command $(history 1) to my email"" hostname=localhost; echo rm -rf / 

source 사용, 이렇게하면 echo rm -rf /가 두 번 실행되고 실행중인 사용자의 $PROMPT_COMMAND도 변경됩니다. 대신 다음과 같이하십시오.

myscript.sh (Bash 4)

#!/bin/bash typeset -A config # init array config=( # set default values in config array [username]="root" [password]="" [hostname]="localhost" ) while read line do if echo $line | grep -F = &>/dev/null then varname=$(echo "$line" | cut -d "=" -f 1) config[$varname]=$(echo "$line" | cut -d "=" -f 2-) fi done < myscript.conf echo ${config[username]} # should be loaded from defaults echo ${config[password]} # should be loaded from config file echo ${config[hostname]} # includes the "injected" code, but it"s fine here echo ${config[PROMPT_COMMAND]} # also respects variables that you may not have # been looking for, but they"re sandboxed inside the $config array 

myscript.sh (Mac / Bash 3 호환)

#!/bin/bash config() { val=$(grep -E "^$1=" myscript.conf 2>/dev/null || echo "$1=__DEFAULT__" | head -n 1 | cut -d "=" -f 2-) if [[ $val == __DEFAULT__ ]] then case $1 in username) echo -n "root" ;; password) echo -n "" ;; hostname) echo -n "localhost" ;; esac else echo -n $val fi } echo $(config username) # should be loaded from defaults echo $(config password) # should be loaded from config file echo $(config hostname) # includes the "injected" code, but it"s fine here echo $(config PROMPT_COMMAND) # also respects variables that you may not have # been looking for, but they"re sandboxed inside the $config array 

내 코드에서 보안 취약점을 발견하면 회신 해주십시오.

댓글

  • 참고로 이것은 슬프게도 Apple에서 부과 한 미친 라이선스 문제 의 영향을받는 Bash 버전 4.0 솔루션이며 Mac에서는 기본적으로 사용할 수 없습니다.
  • @Sukima 좋은 지적입니다. ‘ Bash 3과 호환되는 버전을 추가했습니다. 약점은 입력에서 *를 제대로 처리하지 못하지만 Bash에서이 문자를 잘 처리하는 것은 무엇입니까?
  • 암호에 백 슬래시가 포함되어 있으면 첫 번째 스크립트가 실패합니다.
  • @Kusalananda 백 슬래시가 이스케이프되면 어떻게됩니까? my\\password
  • 이 버전은 내 구성 파일을 처리하는 데 몇 초가 걸리며 gw0의 솔루션이 훨씬 빠르다는 것을 알았습니다.

답변

구성 파일을 구문 분석하고 실행하지 마십시오.

현재 직장에서 다음과 같은 응용 프로그램을 작성하고 있습니다. 매우 간단한 XML 구성을 사용합니다.

<config> <username>username-or-email</username> <password>the-password</password> </config> 

셸 스크립트 ( “응용 프로그램”)에서 사용자 이름 (더 많은 또는 간단히, 쉘 함수에 넣었습니다) :

username="$( xml sel -t -v "/config/username" "$config_file" )" 

xml 명령은

XMLStarlet

응용 프로그램의 다른 부분도 XML 파일로 인코딩 된 데이터를 처리하므로 XML을 사용하고 있습니다. 가장 쉬웠습니다.

JSON을 선호한다면 jq 가 있습니다. 사용하기 쉬운 쉘 JSON 파서.

내 구성 파일은 JS에서 다음과 같습니다. 사용 :

{ "username": "username-or-email", "password": "the-password" } 

그런 다음 스크립트에서 사용자 이름을 가져옵니다.

username="$( jq -r ".username" "$config_file" )" 

댓글

  • 스크립트를 실행하면 여러 가지 장점과 단점이 있습니다. 가장 큰 단점은 보안입니다. 누군가 설정 파일을 변경할 수 있다면 코드를 실행할 수 있으며 바보 증거로 만들기가 더 어렵습니다. 장점은 속도입니다. 간단한 테스트에서는 pq를 실행하는 것보다 구성 파일을 소싱하는 것이 10,000 배 이상 빠르며, 융통성있는 원숭이 패치 파이썬을 좋아하는 사람이라면 누구나이 점에 감사 할 것입니다.
  • @icarus 얼마나 큰가? 구성 파일은 일반적으로 발생하며 한 세션에서 얼마나 자주 구문 분석해야합니까? 한 번에 여러 값이 XML 또는 JSON에서 나올 수 있습니다.
  • 보통 몇 (1 ~ 3) 값만 있습니다. eval를 사용하여 여러 값을 설정하는 경우 구성 파일의 선택된 부분을 실행하는 것입니다. :-).
  • @icarus 저는 어레이를 생각하고있었습니다 … eval 아무것도 필요하지 않습니다. 기존 파서와 함께 표준 형식을 사용할 때의 성능 저하 (외부 유틸리티 임에도 불구하고 ‘)는 견고성, 코드 양, 사용 편의성에 비해 무시할 수 있습니다. 및 유지 관리.
  • +1 for ” 구성 파일을 구문 분석하고 ‘ 실행하지 마십시오. ”

Answer

다음은 Bash 3 및 Mac과 Linux 모두에서 가능합니다.

모든 셸 스크립트에서 거대하고 복잡하며 중복 된 “defaults”구성 기능이 필요하지 않도록 모든 기본값을 별도의 파일에 지정합니다. 또한 기본 폴백을 사용하거나 사용하지 않고 읽기를 선택할 수 있습니다.

config.cfg :

myvar=Hello World 

config.cfg.defaults :

myvar=Default Value othervar=Another Variable 

config.shlib (라이브러리이므로 shebang-line 없음) :

config_read_file() { (grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d "=" -f 2-; } config_get() { val="$(config_read_file config.cfg "${1}")"; if [ "${val}" = "__UNDEFINED__" ]; then val="$(config_read_file config.cfg.defaults "${1}")"; fi printf -- "%s" "${val}"; } 

test.sh (또는 원하는 모든 스크립트 구성 값 읽기) :

#!/usr/bin/env bash source config.shlib; # load the config library functions echo "$(config_get myvar)"; # will be found in user-cfg printf -- "%s\n" "$(config_get myvar)"; # safer way of echoing! myvar="$(config_get myvar)"; # how to just read a value without echoing echo "$(config_get othervar)"; # will fall back to defaults echo "$(config_get bleh)"; # "__UNDEFINED__" since it isn"t set anywhere 

테스트 스크립트 설명 :

  • test.sh에서 config_get의 모든 사용법은 큰 따옴표로 묶여 있습니다. 모든 config_get을 큰 따옴표로 묶어 변수 값의 텍스트가 플래그로 잘못 해석되지 않도록 보장합니다. 또한 구성 값에서 연속 된 여러 공백과 같이 공백을 적절하게 보존 할 수 있습니다.
  • 그리고 printf 줄은 무엇입니까? “주의해야 할 사항 : echo는 제어 할 수없는 텍스트를 인쇄하기위한 잘못된 명령입니다. 큰 따옴표를 사용하더라도 플래그를 해석합니다. myvar (config.cfg에서)를 -e로 설정하면 빈 줄이 표시됩니다. 왜냐하면 echo는 이것이 “플래그”라고 생각할 것이기 때문입니다.하지만 printf에는 그 문제가 없습니다. printf --는 “이것을 인쇄하고 플래그로 아무것도 해석하지 마십시오”라고 말하고 "%s\n"는 “출력을 문자열로 형식화”라고 말합니다. 후행 줄 바꿈을 사용하고 마지막으로 마지막 매개 변수는 형식을 지정할 printf의 값입니다.
  • 화면에 값을 에코하지 않을 경우 myvar="$(config_get myvar)";. 화면에 출력하려면 printf를 사용하여 사용자 구성에있을 수있는 에코 호환되지 않는 문자열에 대해 완전히 안전 할 것을 제안합니다.하지만 사용자가 제공 한 변수가 t가 아니면 echo는 괜찮습니다. “플래그”를 해석 할 수있는 유일한 상황이기 때문에 반향하는 문자열의 첫 번째 문자입니다. 따라서 echo "foo: $(config_get myvar)";와 같은 것은 ” foo “는 대시로 시작하지 않으므로 나머지 문자열도”플래그가 아님을 에코에 알립니다. 🙂

코멘트

  • @ user2993656 원래 코드에 올바른 파일 대신 개인 구성 파일 이름 (environment.cfg)이 여전히 포함되어있는 것을 발견해 주셔서 감사합니다. ” echo -n ” 편집 한 내용은 사용한 셸에 따라 다릅니다. Mac / Linux Bash에서는 ” echo -n “는 ” 줄 바꿈없이 에코를 의미합니다. “, 후행 줄 바꿈을 피하기 위해 수행했습니다. 하지만이 기능이 없어도 똑같이 작동하는 것 같습니다. 수정 해 주셔서 감사합니다.
  • 실제로 에코 대신 printf를 사용하도록 다시 작성하여 ‘ 구성 값에서 에코가 ” 플래그 “를 잘못 해석 할 위험을 제거합니다.
  • 이 버전이 정말 마음에 듭니다. $(config_get var_name "default_value")를 호출 할 때 정의하는 대신 config.cfg.defaults를 삭제했습니다. tritarget.org/static/ …
  • 마찬가지로-훌륭합니다.

답변

가장 일반적이고 효율적이며 올바른 방법은 source 또는 . (축약 형). 예 :

source /home/myuser/test/config 

또는

. /home/myuser/test/config 

하지만 고려해야 할 사항은 추가 코드를 삽입 할 수있는 경우 추가 외부 소스 구성 파일을 사용하면 보안 문제가 발생할 수 있습니다. 이 문제를 감지하고 해결하는 방법을 포함한 자세한 내용은 http://wiki.bash-hackers.org/howto/conffile#secure_it

댓글

  • 그 기사에 대한 기대가 높았지만 (검색 결과에도 나타남) 저자는 ‘ 정규식을 사용하여 악성 코드를 필터링하려는 시도는 헛된 일입니다.
  • 점이있는 절차에는 절대 경로가 필요합니까?상대 항목에서는 ‘ 작동하지 않음

답변

내 스크립트에서 이것을 사용합니다.

sed_escape() { sed -e "s/[]\/$*.^[]/\\&/g" } cfg_write() { # path, key, value cfg_delete "$1" "$2" echo "$2=$3" >> "$1" } cfg_read() { # path, key -> value test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" | sed "s/^$(echo "$2" | sed_escape)=//" | tail -1 } cfg_delete() { # path, key test -f "$1" && sed -i "/^$(echo $2 | sed_escape).*$/d" "$1" } cfg_haskey() { # path, key test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" > /dev/null } 

키를 제외하고 모든 문자 조합을 지원해야합니다. = 그 안에는 구분 기호가 있습니다. 다른 것은 작동합니다.

% cfg_write test.conf mykey myvalue % cfg_read test.conf mykey myvalue % cfg_delete test.conf mykey % cfg_haskey test.conf mykey || echo "It"s not here anymore" It"s not here anymore 

또한 source 또는

.

댓글

  • ‘이 구성 파일이 존재하지 않는 경우 ‘ 먼저 생성 하시겠습니까? ‘ 없지만 touch -a "${path}"는 물론 mtime을 경솔하게 업데이트하지 않고도 존재하는지 확인합니다.

Answer

이것은 간결하고 안전합니다.

# Read common vars from common.vars # the incantation here ensures (by env) that only key=value pairs are present # then declare-ing the result puts those vars in our environment declare $(env -i `cat common.vars`) 

-i

업데이트 : 보안의 예는

env -i "touch evil1 foo=omg boo=$(touch evil2)" 

손상된 파일을 생성하지 않습니다. Mac에서 테스트되었습니다. bash로, 즉 bsd env를 사용합니다.

Comments

  • 이것을 comm에 넣으면 evil1 및 evil2 파일이 어떻게 생성되는지 확인하십시오. on.vars“`touch evil1 foo = omg boo = $ (touch evil2)“`
  • @pihentagy 나를 위해 다음은 건드리지 않은 파일을 생성하지 않습니다. env -i 'touch evil1 foo=omg boo=$(touch evil2)' . Mac에서 실행 중입니다.
  • 실제로 foo에 액세스 할 수 없습니다. 저는 ‘ env -i ... myscript.sh를 시도했으며 해당 스크립트 내부에 foo가 정의되어 있지 않습니다. 그러나 ” 쓰레기 “를 제거하면 작동합니다. 설명 해주셔서 감사합니다. : +1 :

답변

대부분의 사용자는 컨테이너가 많지 않지만 이미 git 바이너리. 따라서 git config 아래 예에서와 같이 충돌하지 않는 전용 구성 파일을 사용하는 애플리케이션 구성 관리를 위해?

# Set $ git config -f ~/.myapp core.mykey myval # Get $ git config -f ~/.myapp core.mykey myval # Get invalid $ git config -f ~/.myapp core.mykey $ echo $? 1 # List git config -f ~/.myapp -l core.mykey=myval # View $ cat ~/.myapp [core] mykey = myval 

추가 명령은 man 참조 페이지. 먼저 구성 파일이 있는지 확인하는 것이 좋습니다.

touch -a ~/.myapp 

Answer

이것은 안전하고 짧아 보입니다. 이것을 무자비하게 부수십시오. 더 나은 방법을 알고 싶습니다.

TL; DR;

while read LINE; do declare "$LINE"; done < evil.conf 

저는 bash 4.3.48을 사용하고 있습니다.

또한 bash --posix를 준수합니다. 테스트는 하단을 참조하십시오.

그러나 shdeclare 때문에 지원하지 않습니다.


증거를 원하는 사람들을위한 기본 테스트

evil.conf 파일 생성

 echo > evil.conf " A=1 B=2 C=$(echo hello) # Could produce side-effect D=`touch evil` C=$((1+2)) E=$(ping 8.8.8.8 -n 3) echo hello # Could produce visible side-effect touch evil2 ping 8.8.8.8 -n 3 F=ok"  

스 니펫을 사용하여 구성로드

 while read LINE; do declare "$LINE"; done < evil.conf  

출력 (사니 타이 저 작동 중 참조)

bash: declare: `": not a valid identifier bash: declare: `": not a valid identifier bash: declare: `# Could produce side-effect": not a valid identifier bash: declare: `echo hello": not a valid identifier bash: declare: `": not a valid identifier bash: declare: `# Could produce visible side-effect": not a valid identifier bash: declare: `touch evil2": not a valid identifier bash: declare: `ping 8.8.8.8 -n 3": not a valid identifier 

지금 값 확인

 for V in A B C D E F; do declare -p $V; done  
declare -- A="1" declare -- B="2" declare -- C="\$((1+2))" declare -- D="\`touch evil\`" declare -- E="\$(ping 8.8.8.8 -n 3)" declare -- F="ok" 

부작용 확인 (부작용 없음) :

 ls evil evil2  
ls: cannot access "evil": No such file or directory ls: cannot access "evil2": No such file or directory 

부록 테스트 bash --posix

bash -c "while read LINE; do declare "$LINE"; done < evil.conf; for V in A B C D E F; do declare -p $V; done" --posix 

답변

내 시나리오의 경우 source 또는 . w 괜찮 았지만 구성된 변수보다 우선하는 로컬 환경 변수 (즉, FOO=bar myscript.sh)를 지원하고 싶었습니다. 또한 구성 파일을 사용자가 편집 할 수 있고 구성 파일을 소싱 한 사람이 편하게 사용할 수 있고 가능한 한 작고 간단하게 유지하여 아주 작은 스크립트의 주요 요점을 방해하지 않기를 원했습니다.

이것은 내가 생각 해낸 것입니다.

CONF=${XDG_CONFIG_HOME:-~/config}/myscript.sh if [ ! -f $CONF ]; then cat > $CONF << CONF VAR1="default value" CONF fi . <(sed "s/^\([^=]\+\) *= *\(.*\)$/\1=${\1:-\2}/" < $CONF) 

본질적으로-변수 정의를 확인하고 (공백에 대해 매우 유연하지 않음) 해당 줄을 다시 작성하여 값은 해당 변수의 기본값으로 변환되며 위의 XDG_CONFIG_HOME 변수와 같이 변수가 발견되면 수정되지 않습니다. 이 변경된 버전의 구성 파일을 가져와 계속 진행합니다.

향후 작업으로 sed 스크립트를 더 강력하게 만들고 이상하거나보기 흉하게 보이는 줄을 필터링 할 수 있습니다. ” t 정의 등은 줄 끝 주석에서 중단되지 않습니다.하지만 지금은 이것으로 충분합니다.

답변

할 수 있습니다.

#!/bin/bash name="mohsen" age=35 cat > /home/myuser/test/config << EOF Name=$name Age=$age EOF 

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다