(하위 쉘의) 함수 호출에서 변수로 stdout을 쉽게 캡처할 수 있습니다.
val="$(get_value)"
셸에서 변수(예: 배열)를 수정할 수도 있습니다.인용하다동일한 셸에서 다음과 같이 가정해 보겠습니다.
function array.delete_by_index {
local array_name="$1"
local key="$2"
unset "$array_name[$key]"
eval "$array_name=(\"\${$array_name[@]}\")"
}
array.delete_by_index "array1" 0
하지만 나는 두 가지를 모두 깔끔한 방법으로 수행하는 방법을 찾으려고 노력하고 있습니다. 내가 원하는 예는 배열에서 값을 팝하는 것입니다.
function array.pop {
local array_name="$1"
local last_index=$(( $(eval "echo \${#$array_name[@]}") - 1 ))
local tmp="$array_name[\"$last_index\"]"
echo "${!tmp}"
# Changes "$array_name" here, but not in caller since this is a sub shell
array.delete_by_index "$array_name" $last_index
}
val="$(array.pop "array1")"
stdout을 변수로 캡처하는 모든 형태에는 bash의 하위 쉘이 필요하며 하위 쉘을 사용하면 호출자의 컨텍스트에서 참조로 값을 변경할 수 없는 것 같습니다.
이것을 달성하기 위한 마법의 배시즘을 아는 사람이 있는지 궁금합니다. 나는 특히 파일 시스템에서 어떤 종류의 파일/fifo를 사용하는 솔루션을 원하지 않습니다.
두 번째 답변이 질문에는이 구성은 분명히 출력 캡처를 허용하지만 하위 쉘을 사용하는 것은 허용하지 않기 때문에 를 ksh
사용하면 이것이 가능하다는 것을 나타내는 것 같습니다 . val="${ cmd; }"
예, 기술적으로는 ksh로 전환할 수 있지만 bash에서 이것이 가능한지 궁금합니다.
답변1
이것은 bash
(버전 4.3부터) 작동하며 ksh93
"bashify"하려면 typeset
전역 범위의 모든 기능을 (모든 옵션을 유지하면서!)로 바꾸십시오. 솔직히 말해서 Bash가 왜 그런 것에만 관심이 있는지 모르겠습니다.local
typeset
declare
typeset
function stack_push
{
typeset -n _stack="$1"
typeset element="$2"
_stack+=("$element")
}
function stack_pop
{
typeset -n _stack="$1"
typeset -n _retvar="$2"
_retvar="${_stack[-1]}"
unset _stack[-1]
}
typeset -a stack=()
stack_push stack "hello"
stack_push stack "world"
stack_pop stack value
printf '%s ' "$value"
stack_pop stack value
printf '%s\n' "$value"
이는 함수에서 nameref를 사용하면 피할 수 있습니다 eval
(저는 eval
어떤 스크립트에서도 이것을 사용한 적이 없습니다!). 함수에 팝된 값을 저장할 장소를 제공 하면 stack_pop
서브셸 사용을 피할 수 있습니다 . 서브쉘을 피함으로써 함수는 stack_pop
외부 범위의 변수 값을 수정할 수 있습니다.stack
함수에서 지역 변수의 밑줄은 nameref가 참조하는 변수와 동일한 이름을 갖는 것을 방지하는 것입니다(Bash는 이를 좋아하지 않습니다. ksh
신경 쓰지 않습니다.이 문제).
ksh
다음과 같이 함수를 작성할 수 있습니다 .stack_pop
function stack_pop
{
typeset -n _stack="$1"
printf '%s' "${_stack[-1]}"
unset _stack[-1]
}
그리고 전화해
printf '%s %s\n' "${ stack_pop stack }" "${ stack_pop stack }"
( ${ ... }
와 동일 $( ... )
하지만 서브쉘을 생성하지 않음)
하지만 나는 이것을 별로 좋아하지 않는다. IMHO 데이터를 stdout으로 보낼 필요가 없으며 데이터를 얻기 stack_pop
위해 호출할 필요도 없습니다 . ${ ... }
나는 원래의 것을 선호 하고 필요할 경우 위의 작업을 수행하는 stack_pop
것을 추가 할 수 있습니다.stack_pop_print
stack_pop
Bash의 경우 게시물 시작 부분에서 를 사용한 다음 스택의 최상위 요소를 삭제하지 않고 stdout에 인쇄하는 을 사용할 수 있습니다 ( 서브셸에서 실행될 stack_top_print
가능성이 높으므로 삭제할 수 없음 ).$( ... )
답변2
파일을 사용하지 않거나 함수를 수정하지 않는 것에 대해 제가 생각할 수 있는 유일한 해결책은 명령을 두 번 실행하는 것입니다. 하나는 하위 쉘에서 캡처하고 다른 하나는 상위 쉘에서 변수를 수정합니다.
val="$(array.pop "array1")" 배열.팝 배열1
함수를 재정의할 수 있는 옵션이 있는 경우:
함수 array.pop { 로컬 배열 이름 = "$1"; Local last_index=$(( $(eval "echo \${#$array_name[@]}") - 1 )); 로컬 tmp="$array_name[\"$last_index\"]"; 에코 "${!tmp}"; 만약 [[ $2 ]]; eval "$2=\"${!tmp}\"" # 여기에 마법 공격이 있습니다. 필리핀 제도 array.delete_by_index "$array_name" "$last_index"; }
다음으로 실행하면 array.pop 'array1' variablename
변수가 존재하지 않더라도 변수가 초기화됩니다.
$array1=(하나 둘 셋) $array.pop array1 var 삼 $echo "$var" 삼 $ echo "${array1[*]}" 하나 또는 둘