dd 스타일 bash 스크립트에 매개변수를 전달하고 싶습니다. 기본적으로 나는 원한다
./script a=1 b=43
같은 효과가 있다
a=1 b=43 ./script
나는 다음과 같은 방법으로 이를 달성할 수 있다고 생각합니다.
for arg in "$@"; do
eval "$arg";
done
eval
안전한 (즉, "$arg"
정적 일치(코드 실행 없음)) 변수 할당을 보장하는 좋은 방법은 무엇입니까?
아니면 더 좋은 방법이 있나요? (간단하게 유지하고 싶었습니다).
답변1
eval 없이(및 수동 이스케이프 없이) bash에서 이 작업을 수행할 수 있습니다.
for arg in "$@"; do
if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; then
declare +i +a +A "$arg"
fi
done
편집하다:Stéphane Chazelas의 의견에 따라 할당된 변수가 배열 또는 정수 변수로 선언되는 것을 방지하기 위해 선언에 플래그를 추가했습니다. 이렇게 하면 많은 경우 인수의 값 부분을 declare
평가 하지 않게 됩니다 key=val
. ( +a
예를 들어 설정할 변수가 배열 변수로 선언된 경우 오류가 발생합니다.) 이러한 모든 취약점은 이 구문을 사용하여 기존(배열 또는 정수) 변수를 재할당하는 것과 관련이 있습니다. 쉘 변수로 알려져 있습니다.
실제로 이는 동일한 eval
솔루션에 영향을 미치는 주입 공격 클래스의 한 예일 뿐입니다. 알려진 매개변수 이름만 허용하는 것이 명령줄에 나타나는 변수를 맹목적으로 설정하는 것보다 훨씬 낫습니다. ( PATH
예를 들어, 명령줄에서 설정했다면 어떤 일이 일어날지 생각해 보세요. 또는 PS1
다음 프롬프트가 표시될 때 발생할 일부 평가를 포함하도록 재설정하세요.)
저는 bash 변수를 사용하는 것보다 명명된 매개변수의 연관 배열을 사용하는 것을 선호합니다. 이는 설정하기 쉽고 안전합니다. 또는 실제 bash 변수를 설정할 수 있지만 해당 이름이 유효한 인수의 연관 배열에 있는 경우에만 가능합니다.
후자 접근 방식의 예는 다음과 같습니다.
# Could use this array for default values, too.
declare -A options=([bs]= [if]= [of]=)
for arg in "$@"; do
# Make sure that it is an assignment.
# -v is not an option for many bash versions
if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= &&
${options[${arg%%=*}]+ok} == ok ]]; then
declare "$arg"
# or, to put it into the options array
# options[${arg%%=*}]=${arg#*=}
fi
done
답변2
POSIX 1( / ... 와 같은 특수 변수 관련 문제를 피하기 $<prefix>var
보다는 설정 ):$var
IFS
PATH
prefix=my_prefix_
for var do
case $var in
(*=*)
case ${var%%=*} in
"" | *[!abcdefghijiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]*) ;;
(*) eval "$prefix${var%%=*}="'${var#*=}'
esac
esac
done
으로 호출되며 myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2
다음을 할당합니다.
my_prefix_x <= 1
my_prefix_PATH <= /tmp/evil
my_prefix_1 <= 2
답변3
하드코딩된 접두사로 리팩터링된 lcd047의 솔루션 DD_OPT_
:
while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
done
프로스트슈츠리팩토링의 대부분은 칭찬받을 가치가 있습니다.
소스 파일에 전역 변수로 넣었습니다.
DD_OPTS_PARSE=$(cat <<'EOF'
while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
done
EOF
)
eval "$DD_OPTS_PARSE"
모든 마법을 발휘해보세요.
함수 버전은 다음과 같습니다.
DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"
사용 중:
eval "$DD_OPTS_PARSE_LOCAL"
내가 하나 만들었어환매 계약그 외에도 테스트와 README.md가 있습니다. 그런 다음 작성 중이던 Github API CLI 래퍼에서 이것을 사용했고, 위의 github 클론을 설정하는 데 동일한 래퍼를 사용했습니다.환매 계약(부팅하는 것은 재미 있습니다).
bash 스크립트에 인수를 안전하게 전달하는 데는 한 줄이면 충분합니다. 즐기다. :)
답변4
내 시도:
#! /usr/bin/env bash
name='^[a-zA-Z][a-zA-Z0-9_]*$'
count=0
for arg in "$@"; do
case "$arg" in
*=*)
key=${arg%%=*}
val=${arg#*=}
[[ "$key" =~ $name ]] && { let count++; eval "$key"=\$val; } || break
# show time
if [[ "$key" =~ $name ]]; then
eval "out=\${$key}"
printf '|%s| <-- |%s|\n' "$key" "$out"
fi
;;
*)
break
;;
esac
done
shift $count
# show time again
printf 'arg: |%s|\n' "$@"
RHS의 거의 모든 쓰레기를 처리할 수 있습니다.
$ ./assign.sh Foo_Bar33='1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0' '1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33'
|Foo_Bar33| <-- |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0|
arg: |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33|
$ ./assign.sh a=1 b=2 c d=4
|a| <-- |1|
|b| <-- |2|
arg: |c|
arg: |d=4|