Bash - 쉘 변수의 함수

Bash - 쉘 변수의 함수

나는 이것을 읽고 있다우편 엽서Bash 쉘 변수에서 함수 사용에 대해. 쉘 함수를 사용하려면 다음과 같이 해당 함수를 내보내고 서브쉘에서 실행해야 한다는 것을 알았습니다.

$ export foo='() { echo "Inside function"; }'
$ bash -c 'foo'
Inside function

내보내기를 사용하거나 새 쉘을 실행하지 않고도 현재 쉘에서 실행될 수 있도록 bash 쉘 변수에 함수를 정의할 수 있는지 묻고 싶습니다.

답변1

아니 당신은 할 수 없습니다.

현재 셸에서 함수를 사용하려면 함수를 정의한 다음 사용하세요.

$ foo() { echo "Inside function"; }
$ foo
Inside function

앞으로쉘 쇼크이제 변수에 함수를 저장하고, 변수를 내보내고, 서브셸에서 함수를 사용할 수 있습니다. 내보낸 bash함수가 지원되므로bash함수 정의를 환경 변수에 넣습니다.좋다:

foo=() {
  echo "Inside function"
}

=그런 다음 함수는 공백으로 대체하여 해석됩니다. 함수를 변수에 넣고 변수를 참조하여 함수를 실행하려는 의도는 없습니다.

지금, 이후스티븐 차제라스오류가 발견되었습니다.이 기능은 제거되었습니다., 함수 정의는 더 이상 일반 환경 변수에 저장되지 않습니다. 이제 내보낸 함수는 환경 변수와의 충돌을 피하기 위해 BASH_FUNC_접두사와 접미사가 추가되어 인코딩됩니다 . 이제 인터프리터는 변수의 내용에 관계없이 쉘 함수인지 여부를 결정할 수 있습니다. 또한 서브셸에서 사용하려면 함수를 정의하고 명시적으로 내보내야 합니다.%%bash

$ foo() { echo "Inside function"; }
$ export -f foo
$ bash -c foo
Inside function

어쨌든, 귀하의 예제가 현재 버전에서 작동한다면 bash취약한 버전을 사용하고 있는 것입니다.

답변2

foo='foo(){ echo "Inside Function"; }'
bash -c "$foo; foo"

Inside Function

결국, 함수는 이름이 지정되고 미리 구문 분석된 정적 명령 문자열이며 쉘 메모리에 저장되어 있습니다. 따라서 유일한 실제 방법은 문자열을 코드로 평가하는 것입니다. 이는 쉘이 함수를 호출할 때마다 수행하는 것과 정확히 같습니다.

이전에도 다르지 않았고 지금도 그렇습니다. 개발자들은 이를 위해 편리한 방법을 만들어왔고, 발생할 수 있는 보안 허점을 최대한 방지하려고 노력하지만, 사실은 편리할수록 그에 대해 알아야 할 것보다 더 적게 알 가능성이 높습니다.

가지다많은상위 셸에서 하위 셸로 데이터를 가져올 때 사용할 수 있는 옵션입니다. 이에 익숙해지고, 잠재적인 용도와 잠재적인 약점을 인식할 만큼 자신감을 갖고, 조심스러우면서도 효과적으로 사용하십시오.


토론 중에 한두 가지에 대해 자세히 설명할 수 있을 것 같습니다. 아마도 한 셸에서 다른 셸로 정적 명령을 전달하는 가장 좋은 방법일 것입니다.(하위 쉘 명령 체인의 업스트림 또는 다운스트림)alias. alias이 경우에 유용합니다.POSIX 지정이를 정의하는 명령을 보고합니다.안전하게:

별칭을 표시하기 위한 형식(피연산자가 지정되지 않거나 이름 피연산자만 지정된 경우)은 다음과 같아야 합니다.

  • "%s=%s\n", name, value

이것문자열은 쉘에 다시 입력하기에 적합하도록 적절한 따옴표로 작성되어야 합니다. 쉘 인용 설명 보기인용하다.

예를 들어:

alias foo="foo(){ echo 'Inside Function'; }"
alias foo

foo='foo(){ echo '\''Inside Function'\''; }'

그것이 따옴표에 어떤 영향을 미치는지 보시겠습니까? 정확한 출력은 셸에 따라 다르지만 일반적으로 셸을 사용하여 다시 입력할 수 있는 alias안전한 방법으로 정의를 보고 할 수 있습니다.eval동일한껍데기. 그러나 어떤 경우에는 소스/대상 쉘을 혼합하고 일치시키면 문제가 발생할 수 있습니다.

이러한 신중한 접근 방식을 정당화하려면 다음을 수행하십시오.

ksh -c 'alias foo="
    foo(){
        echo \"Inside Function\"
    }"
    alias foo'

foo=$'\nfoo(){\n\techo "Inside Function"\n}'

또한 alias네임스페이스는 세 가지 별도의 네임스페이스 중 하나를 나타내며 일반적으로 거의 모든 최신 셸에서 완전히 구체화된 네임스페이스를 찾을 수 있다고 기대할 수 있습니다. 일반적으로 셸은 다음 세 가지 네임스페이스를 제공합니다.

  • 변하기 쉬운:name=value밖의목록

    • 경우에 따라 이는 내장 함수(예: )를 사용하여 정의할 수도 있습니다 export.setreadonly
  • 기능:name() compound_command <>any_redirects존재하다명령 위치

    • 쉘이 지정됨아니요정의된 명령에서 발견될 수 있는 함수 정의의 일부를 확장하거나 해석합니다.
      • 그러나 이 금지에는 별칭이 포함되지 않습니다. 별칭은 쉘 명령 읽기를 구문 분석하는 동안 확장되므로 alias값이 올바른 컨텍스트에서 발견되면 alias발견 시 함수 정의 명령으로 확장됩니다.
    • 앞에서 언급했듯이 셸은 정의 명령의 구문 분석된 값을 메모리에 정적 문자열로 유지하며 나중에 호출 후 구문 분석 후 함수 이름이 발견되는 경우에만 문자열에서 발견된 모든 확장 및 확장을 수행합니다. .
  • 별명:alias name=value존재하다명령 위치

    • 함수와 마찬가지로 alias정의는 나중에 명령 위치에서 해당 이름을 찾을 때 해석됩니다.
    • 그러나 함수와 달리 명령에 대한 인수로 정의되므로 alias해당 함수 내에서 발견된 유효한 셸 확장도 정의 시 해석됩니다. 따라서 alias정의는 항상 두 번 해석됩니다.
    • 함수와 달리 alias정의는 정의될 때 전혀 구문 분석되지 않지만 쉘의 구문 분석기는 해당 값을 찾으면 해당 값을 명령 문자열로 준비합니다.

alias위의 an 또는 a 함수 사이의 주요 차이점, 즉 각 함수의 셸 확장 지점을 고려한 내용을 눈치챘을 것입니다 . 실제로 이러한 차이점은 이들의 조합을 매우 유용하게 만들 수 있습니다.

alias foo='
    foo(){
        printf "Inside Function: %s\n" "$@"
        unset -f foo
    };  foo "$@" '

이는 호출 시 자신을 설정 해제하는 함수를 정의하는 별칭이므로 다른 네임스페이스를 적용하여 한 네임스페이스에 영향을 줍니다. 그런 다음 함수를 호출합니다. 이 예는 일반적인 상황에서는 별로 유용하지 않지만 다음 예에서는 다른 상황에서 제공할 수 있는 제한된 유용성을 보여줄 수 있습니다.

sh -c "
    alias $(alias foo)
    foo \'
" -- \; \' \" \\

Inside Function: ;
Inside Function: '
Inside Function: "
Inside Function: \
Inside Function: '

alias정의된 이름을 찾기보다는 항상 입력 라인에서 이름을 호출해야 합니다 . 이는 명령이 구문 분석되는 순서와 관련이 있습니다. 함께 사용하면 별칭과 함수를 함께 사용하여 정보와 매개변수 배열을 하위 쉘 컨텍스트 안팎으로 이동 가능하고 안전하며 효율적으로 이동할 수 있습니다.


관련성이 거의 없지만 여기에 또 다른 흥미로운 것이 있습니다.

alias mlinesh='"${SHELL:-sh}" <<"" '

대화형 프롬프트에서 실행하면 호출된 줄과 동일한 실행 줄에서 전달된 모든 인수가 하위 쉘에 대한 인수로 해석됩니다. 그러나 빈 줄이 처음 나타날 때까지의 모든 후속 줄은 현재 셸에서 읽고 호출 중인 하위 셸에 표준 입력으로 전달되며 어떤 방식으로도 해석되지 않습니다.

$ mlinesh -c '. /dev/fd/0; foo'
> foo(){ echo 'Inside Function'; } 
> 

Inside Function

...오직...

$ mlinesh
> foo(){ echo 'Inside Function'; }
> foo
> 

...더 쉽게...

관련 정보