내 스크립트에 대한 구성 파일을 만들어야합니다. 여기 예가 있습니다.
스크립트:
#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2
내용 /home/myuser/test/config
:
nam="Mark"
sur="Brown"
작동합니다!
내 질문 : 이것이 올바른 방법입니까 아니면 다른 방법이 있습니까?
답변
source
임의의 코드를 실행하므로 안전하지 않습니다. 이는 걱정할 사항이 아니지만 파일 사용 권한이 올바르지 않은 경우 파일 시스템 액세스 권한이있는 공격자가 다음과 같이 보안이 설정된 스크립트에 의해로드 된 구성 파일에 코드를 삽입하여 권한있는 사용자로 코드를 실행할 수 있습니다. 초기화 스크립트.
지금까지 내가 찾은 최고의 솔루션은 서투른 재발견 솔루션입니다.
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 (배시 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
내 코드에서 보안 취약점을 발견하면 회신하십시오.
답변
Mac 및 Linux 모두에서 Bash 3 이상과 호환되는 깨끗하고 이식 가능한 버전이 있습니다.
모든 셸 스크립트에서 복잡하고 복잡한 중복 된 “기본”구성 기능이 필요하지 않도록 모든 기본값을 별도의 파일로 지정합니다. 또한 기본 폴백을 사용하거나 사용하지 않고 읽을 수 있습니다.
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
(inconfig.cfg
)을 (를 ) 설정-e
하면 빈 줄echo
이 표시됩니다. 이는 플래그라고 생각 하기 때문 입니다. 그러나printf
그 문제는 없습니다. 는printf --
“이 인쇄 및 플래그 등 아무것도 해석하지 않는다”라는, 그리고는"%s\n"
뒤에 개행 문자의 문자열로 출력 형식 “라고, 그리고 마지막으로 최종 매개 변수는 형식의 printf의 값입니다. - 화면에 값을 표시하지 않으려면 다음과 같이 정상적으로 값을 지정하면됩니다
myvar="$(config_get myvar)";
. 화면에 인쇄하려는 경우 printf를 사용하여 사용자 구성에있을 수있는 에코 호환되지 않는 문자열에 대해 완전히 안전합니다. 그러나 사용자가 제공 한 변수 가 반향하고있는 문자열의 첫 번째 문자 가 아닌 경우 반향은 괜찮습니다 . “플래그”가 해석 될 수있는 유일한 상황이므로echo "foo: $(config_get myvar)";
“foo”는 그렇지 않기 때문에 안전합니다. 대시로 시작하므로 나머지 문자열도 플래그가 아니라고 에코에 알립니다. 🙂
답변
구성 파일을 구문 분석하고 실행하지 마십시오.
현재 매우 간단한 XML 구성을 사용하는 직장에서 응용 프로그램을 작성 중입니다.
<config>
<username>username-or-email</username>
<password>the-password</password>
</config>
쉘 스크립트 ( “응용 프로그램”)에서 이것은 사용자 이름을 얻기 위해 수행하는 것입니다 (더 많거나 적은, 쉘 함수에 넣었습니다).
username="$( xml sel -t -v '/config/username' "$config_file" )"
이 xml
명령은 대부분의 Unices 에서 사용할 수있는 XMLStarlet 입니다.
응용 프로그램의 다른 부분도 XML 파일로 인코딩 된 데이터를 처리하므로 XML을 사용하므로 가장 쉽습니다.
JSON을 선호한다면 jq
쉘 JSON 파서를 사용하기 쉽습니다.
내 구성 파일은 JSON에서 다음과 같습니다.
{
"username": "username-or-email",
"password": "the-password"
}
그런 다음 스크립트에서 사용자 이름을 얻습니다.
username="$( jq -r '.username' "$config_file" )"
답변
가장 일반적인, 효율적이고 올바른 방법은 사용하는 것입니다 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
/도 사용하지 않기 때문에 완전히 안전합니다.eval
답변
내 시나리오에서 source
또는 .
괜찮 았지만 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
스크립트를보다 견고 하게하고 이상한 모양이나 정의가 아닌 줄을 필터링하여 줄 끝에서 끊지 않을 수는 있지만 현재로서는 충분합니다.
답변
간결하고 안전합니다.
# 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
통해 변수를 얻을 수 있습니다.common.vars