배쉬 4를 사용하고 있습니다.
Bash로 몇 가지 실험을 하려고 합니다. 변수 값에 배열을 동적으로 할당하고 싶습니다. 아래 코드를 읽어보시면 이해가 더 쉬울 것입니다.
myFunc =RESULT_PREF 'bar' 'baz'
function myFunc() {
local params
parser params "$@"
}
function parser() {
if [ '=' = "${2::1}" ]; then
local name="${1}"
shift 2
local param_array=( "$@" )
# In PHP, I'd do:
# $$name = $param_array
# The ideal outcome:
# $params should contain the values 'bar' and 'baz'.
fi
}
코드 주석에서 언급한 내용을 어떻게 수행할 수 있나요? 이 작업을 수행하기 위해 eval을 사용할 수 없는 것 같습니다. 가능하더라도 평가에 관한 나쁜 내용을 많이 읽었습니다.
어떤 제안이 있으십니까?
답변1
Bash 4.3+에는 변수 참조를 정의하는 방법이 있습니다. 다음에서 확인할 수 있습니다 help declare
.
-N: NAME을 값의 이름이 지정된 변수에 대한 참조로 만듭니다.
따라서 이와 같은 스크립트는 한 줄을 출력합니다 a
.
n(){ declare -n g="$1"; g=a; }
n b; printf '%s\n' "$b";
그래서 당신은 이렇게 해야 합니다 parser
:
parser() {
[ "$1" ] || ! echo 'no name given' >&2 || return 42
if [[ "$2" == =* ]]; then
declare -n name="$1"
shift 2
name=("$@")
fi
}
다음 을 사용하면 eval
작동하지만 rhs가 너무 일찍 확장되면 안전하지 않을 수 있습니다.
shopt -e extglob # bash >= 3
[[ "$1" == [[:alpha:]_]*([[:word:]]) ]] || return 42 # invalid varname
# mikeserv has another solution for filtering, basically expanding
# the inverse of the expression to basic, portable globs
# Do this:
eval "$1"'=( "$@" )'
eval "$foo=\$bar"
# But not:
eval "$1=(\"$@\")"
eval "$foo=$bar"
그러면 무엇을 해야 할지 알게 될 것 같아요 eval
. 하지만 여러분이 내 대답을 받아들일 가능성을 더 높이기 위해 전체 내용을 작성해 보겠습니다.
shopt -s extglob
parser() {
[[ "$1" == [[:alpha:]_]*([[:word:]]) ]] || ! echo 'bad varname' >&2 || return 42
if [[ "$2" == =* ]]; then
name="$1"
shift 2
eval "$name=(\"\$@\")"
fi
}
답변2
myFunc(){
parse "$1" && #parse() is a test
eval " shift #$1 is a valid, eval-safe name
local name$1 ${1#=}="'("$@")' #$1 is expanded before shift
}
parse()
case ${1#=} in
("$1"|""|[0-9]*|*[!_[:alnum:]]*) ! : #return false for all invalid names
esac
또한 eval
하나 또는 두 개의 실행 단계를 더 제공하지 않고도 작동합니다.
myFunc(){
local -a "name$1[@]" "${1#=}"='("${@:2}")' &&
[ -z "${1%=*}" ] && printf %s\\n "${!name}"
}
local
이 경우에는 내장 함수가 모든 검증과 할당을 즉시 수행하도록 허용합니다 . 기본적으로 local
명령을 "${1#=}"=("${@#"$1"}")
성공적으로 할당할 수 있는 경우그리고 "${1%=*}"
null이면 할당이 성공적으로 발생한 것입니다. 구문 오류(예: 잘못된 쉘 이름)는 할당 return
중 오류로 인해 자동으로 실패 하며, 실수로 수행하지 않도록 하기 위해 local
다음으로 간단한 확인 [
테스트가 모두 필요합니다 .]
local name=morename=("${@#"$1"}")
자연스러운 결과는 나쁜 이름이 있을 때입니다.예들어오는 =$1
쉘은 의미 있는 오류 메시지를 stderr에 자동으로 인쇄하고 모든 오류 처리를 자동으로 수행합니다.
이와 같이:
myFunc =goodname 1 2 3 'and some ;more' &&
myFunc =bad-name 1 2 3 'and some ;more'
1 2 삼 더 많은 것이 있습니다. bash: local: `bad-name=("${@:2}")': 유효한 식별자가 아닙니다.
그렇게 해주세요function
name
(){
list
;}
그것은 당신이 원하는 것이 거의 확실하지 않습니다.
함수 트랩 등을 현지화하려는 경우 다음이 필요합니다.function
name
{
list
;}
.
local
정의한 변수를 제외한 모든 상태를 현재 셸과 공유 하려는 경우function
name
(){
list
;}
또는name
()
list
function
쉘에서 키워드를 무시하기 때문에 동일합니다.(이를 구현하는 일부 쉘을 제외하고 다음을 구문 분석하는 경향이 있습니다.list
중괄호로 묶지 않으면 오류 발생)언제name
다음은 입니다 ()
.