bash: 내보낸 함수는 표시되지 않지만 변수는 표시됩니다.

bash: 내보낸 함수는 표시되지 않지만 변수는 표시됩니다.

수년에 걸쳐 저는 쉘과 스크립트에서 참조하는 bash 함수 라이브러리를 수집했습니다. 상용구 가져오기를 줄이기 위해 스크립트에 라이브러리를 현명하게 포함하는 방법에 대한 옵션을 탐색하고 있습니다.

내 솔루션은 두 부분으로 구성됩니다. 먼저 구성(환경 변수)을 가져온 다음 함수 라이브러리를 가져옵니다.

~/bash_envs: (구성)

export SOME_VAR=VALUE
export SHELL_LIB=/path/to/library.sh

# convenience funtion, so scripts who source env_vars file (ie this file) can
# simply call it, instead of including the same block in each file themselves.
function _load_common() {
    # import common library/functions:
    source $SHELL_LIB
}
export -f _load_common

# marker var used to detect whether env vars (ie this file) have been loaded:
export __ENV_VARS_LOADED_MARKER_VAR=loaded

이제 스크립트에서 다음 코드를 실행합니다.

if [[ "$__ENV_VARS_LOADED_MARKER_VAR" != loaded ]]; then  # in our case $__ENV_VARS_LOADED_MARKER_VAR=loaded, ie this block is not executed
    USER_ENVS=/home/laur/bash_envs

    if [[ -r "$USER_ENVS" ]]; then
        source "$USER_ENVS"
    else
        echo -e "\n    ERROR: env vars file [$USER_ENVS] not found! Abort."
        exit 1
    fi
fi

_load_common

_load_common: command not found그러면 예외가 생성됩니다 . 왜 그런 겁니까? 주석은 __ENV_VARS_LOADED_MARKER_VAR=loaded잘 내보내지고 표시되므로 source 할 이유가 없지만 __ENV_VARS_LOADED_MARKER_VAR과 동일한 위치에서 내보내졌음에도 불구하고 함수를 찾을 수 없습니다 $USER_ENVS._load_common()

답변1

질문

관찰하다:

$ bash -c 'foobar () { :; }; export -f foobar; dash -c env' |grep foobar
$ bash -c 'foobar () { :; }; export -f foobar; bash -c env' |grep foobar
BASH_FUNC_foobar%%=() {  :
$ bash -c 'foobar () { :; }; export -f foobar; ksh93 -c env' |grep foobar
BASH_FUNC_foobar%%=() {  :
$ bash -c 'foobar () { :; }; export -f foobar; mksh -c env' |grep foobar
$ bash -c 'foobar () { :; }; export -f foobar; zsh -c env' |grep foobar
BASH_FUNC_foobar%%=() {  :
$ bash -c 'foobar () { :; }; export -f foobar; busybox sh -c env' |grep foobar
BASH_FUNC_foobar%%=() {  :

환경 변수는 Unix 운영 체제의 기능입니다. 이에 대한 지원은 커널까지 확장됩니다. 즉, 한 프로그램이 다른 프로그램을 호출할 때(다음을 사용하여)execve시스템 호출), 호출 매개변수 중 하나는 새 프로그램의 환경입니다.

sh 스타일 셸(dash, bash, ksh 등)에 내장된 명령을 사용하면 export셸 변수가 환경 변수로 사용되어 셸이 호출하는 프로세스로 전송됩니다. 대신, 쉘이 호출되면 모든 환경 변수는 해당 쉘 인스턴스의 쉘 변수가 됩니다.

함수 내보내기는 bash의 기능입니다. Bash는 이름이 함수 이름에서 파생되고 값이 함수 본문(헤더 및 트레일러 포함)인 환경 변수를 생성하여 함수를 "내보냅니다". 위에서 환경 변수의 이름이 어떻게 구성되는지 볼 수 있습니다. BASH_FUNC_그 다음에는 함수의 이름이 있습니다 %%.

이 이름은 쉘 변수의 유효한 이름이 아닙니다. 쉘은 시작 시 환경 변수를 쉘 변수로 가져옵니다. 환경 변수의 이름이 유효한 쉘 변수가 아닌 경우 쉘마다 동작이 다릅니다. 일부는 변수를 하위 프로세스(위: bash, ksh93, zsh, BusyBox)에 전달하는 반면 다른 일부는 내보낸 셸 변수를 하위 프로세스(위: dash, mksh)에 전달하여 a 이외의 이름을 가진 환경 변수가 효과적으로 제거되었습니다. 유효한 쉘 변수(비어 있지 않은 ASCII 문자, 숫자 및 시퀀스 _).

원래 bash는 함수와 동일한 이름을 가진 환경 변수를 사용하여 기본적으로 이 문제를 피했습니다. (대부분의 경우에만: 함수 이름에는 셸 변수 이름에 허용되지 않는 문자가 포함될 수 있습니다(예: ) -.) 그러나 여기에는 동일한 이름의 셸 변수 및 함수 내보내기를 허용하지 않는 등의 다른 단점이 있습니다(마지막으로 내보낸 이름이 정확함). )는 환경의 다른)을 덮어씁니다. 결정적으로 bash가 변경되었습니다.원래 구현으로 인해 심각한 보안 취약점이 발견되었습니다.. (당신은 또한 볼 수 있습니다env x='() { ::}; 무슨 뜻인가요? bash 명령은 무엇을 하며 왜 안전하지 않습니까?,Shellshock(CVE-2014-6271/7169) 버그는 언제 소개되었나요? 이 버그를 완전히 수정한 패치는 무엇인가요?,Shellshock Bash 취약점은 어떻게 발견되었습니까?) 이 변경의 한 가지 단점은 내보낸 기능이 더 이상 dash 및 mksh를 포함한 일부 프로그램을 통과하지 못한다는 것입니다.

시스템에 대시가 있을 수 있습니다 /bin/sh. 이것은 매우 인기있는 선택입니다. 많이 사용되므로 호출 경로 어딘가에서 /bin/sh함수를 사용하려고 하는 bash 인스턴스로 실행되었던 원래 bash 인스턴스가 호출되었을 가능성이 높습니다 . 유효한 변수 이름이 있으므로 통과하지만 통과하지 못합니다.shexport -f _load_common__ENV_VARS_LOADED_MARKER_VARBASH_FUNC__load_common%%

해결책

내보낸 함수를 사용하지 마세요. 우선 그들은 쓸모가 없습니다. 그들은 당신에게 전혀 쓸모가 없습니다. 함수 내보내기의 유일한 장점은 bash를 호출할 때 스크립트에서 함수를 정의하고 이를 find -exec또는 에서 xargs호출되는 bash 인스턴스 에 전달하는 등 어딘가에서 함수 정의를 읽기 위해 bash 인스턴스가 필요하지 않다는 것입니다 parallel. 그러나 귀하의 경우에는 함수 정의를 읽는 코드가 이미 있습니다. 그러니 무조건 함수 정의를 읽어보세요. 삭제 export -f _load_common하고 삭제한 __ENV_VARS_LOADED_MARKER_VAR다음 호출하세요 source "$USER_ENVS".

관련 정보