bash에서 함수를 "내보내기"할 수 있습니까?


80
source some_file

some_file :

doit ()
{
  echo doit $1
}
export TEST=true

나는 소스 경우 some_file 기능 "작은 동전"과 변수 TEST 명령 줄에서 사용할 수 있습니다. 그러나이 스크립트를 실행 :

script.sh :

#/bin/sh
echo $TEST
doit test2

TEST 값을 반환하지만 알 수없는 함수 "doit"에 대한 오류를 생성합니다.

함수를 "내보내기"할 수 있습니까, 아니면 script.sh에서 some_file을 소싱하여 함수를 사용해야합니까?


2
변화 : 아래의 답변을 (질문 표시로 enzotib, 당신은 떠들썩한 파티를 사용할 수 있습니다 가정, 올바른) 요약 #!/bin/sh#!/bin/bash doit() {...} 바로export -f doit
마이클

기록을 위해서만 :이 솔루션은 일반적으로 #!/bin/sh너무 사용할 때 작동 하지만 #!/bin/bash기본 쉘이 bash가 아닌 경우 문제를 피할 수 있도록 사용하는 것이 좋습니다 .
Nagel

답변:


119

Bash에서 함수 정의를 하위 쉘로 내보낼 수 있습니다.

export -f function_name

예를 들어 다음과 같은 간단한 예를 시도해보십시오.

./script1:

    #!/bin/bash

    myfun() {
        echo "Hello!"
    }

    export -f myfun
    ./script2

./script2:

    #!/bin/bash

    myfun

그런 다음 전화 ./script1하면 Hello! 출력이 표시됩니다 . .


16

를 사용하여 함수를 "내보내기" export -f는 함수 본문과 함께 환경 변수 를 만듭니다. 이 예제를 고려하십시오.

$ fn(){ echo \'\"\ \ \$; }
$ export -f fn
$ sh -c printenv\ fn
() {  echo \'\"\ \ \$
}

이것은 쉘 (Bash?) 만 기능을 받아 들일 수 있다는 것을 의미합니다. Bash는 함수로 시작하는 envvar 만 고려하므로 함수를 직접 설정할 수도 있습니다 () {.

$ fn2='() { echo Hi;}' sh -c fn2
Hi
$ fn3='() {' sh -c :
sh: fn3: line 1: syntax error: unexpected end of file
sh: error importing function definition for `fn3'

SSH를 통해이 변수를 "내보내기"해야하는 경우 실제로 문자열로 함수가 필요합니다. 내장 -p기능 ( -f)에 대한 인쇄 옵션 ( ) 으로 수행 할 수 있습니다 declare.

$ declare -pf fn
fn () 
{ 
    echo \'\"\ \ \$
}

SSH를 통해 실행해야하는보다 복잡한 코드가있는 경우 매우 유용합니다. 다음과 같은 가상 스크립트를 고려하십시오.

#!/bin/bash
remote_main() {
   local dest="$HOME/destination"

   tar xzv -C "$dest"
   chgrp -R www-data "$dest"
   # Ensure that newly written files have the 'www-data' group too
   find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"

fn2='() { echo Hi;}' sh -c fn2나를 위해 일하지 않았다. shbash v5.0.7 인 아치 리눅스에서 나는 얻었다 sh: fn2: command not found. sh대시 v0.2.3으로 우분투에서 나는 얻었다 sh: 1: fn2: not found. 어떤 sh쉘을 사용 했습니까?
Socowi

당신의 대답이 틀렸다고 생각합니다. f(){ echo a;}; export -f f; echo "$f"; sh -c 'printenv f; echo "$f"'나를 위해 아무것도 인쇄하지 않으므로 분명히 f일반 문자열로 내보내지지 않습니다. 위에서 언급 한 두 가지 조합으로 테스트했습니다.
Socowi

그리고 함수를 문자열로 내 보낸 경우에도 sh해당 문자열을 함수로 실행 해야하는 이유는 무엇입니까? 귀하의 예 fn2='() { echo Hi;}' sh -c fn2에서 fn2주어진 명령 sh 은 문자 그대로 문자열 "fn2"입니다. shPATH에서 이러한 명령을 검색해야하지만 변수가 있는지 확인 하지 말고 해당 변수 $fn2를 확장하고 값을 함수로 실행하십시오. 주요 보안 문제처럼 들립니다. 편집 : 그게 다야! 표시된 동작이 ShellShock / Bashdoor 로 알려진 보안 버그 입니까?
Socowi

Bash 5.0.7 (Arch Linux)에서는 접두사가 앞에 추가 된 것으로 보입니다. 이것은 ShellShock에 대한 응답으로 수행 된 것 같습니다. 예 : fn(){ echo foo; }; export -f fn; env | grep foo출력BASH_FUNC_fn%%=() { echo foo
Lekensteyn

7

에 구축 Lekensteyn의 대답 @ ...

사용 declare -pf하면 현재 쉘에서 이전에 정의 된 모든 기능을 STDOUT으로 출력합니다.

이 시점에서 STDOUT을 원하는 곳으로 리디렉션 할 수 있으며 원하는 곳에서 이전에 정의 된 기능을 적용 할 수 있습니다.

다음 답변은 변수에 넣습니다. 그런 다음 해당 변수와 새 사용자로 생성 된 새 셸에 실행하려는 함수의 호출을 에코합니다. 우리는 사용하여이 작업을 수행 할 sudo-u(일명. user) 스위치와 단순히 (실행할 수있는 입력으로 파이프 STDOUT을받을 것이다) 배쉬를 실행.

우리가 Bash 쉘에서 Bash 쉘로 가고 있음을 알 때 Bash가 이전 쉘 정의 함수를 올바르게 해석한다는 것을 알고 있습니다. 동일한 버전의 하나의 Bash 쉘을 동일한 버전의 새로운 Bash 쉘로 이동하는 한 구문은 양호해야합니다.

다른 쉘 또는 다른 버전의 Bash가있는 시스템간에 이동하는 경우 YMMV

#!/bin/bash
foo() {
  echo "hello from `whoami`"
}

FUNCTIONS=`declare -pf`; echo "$FUNCTIONS ; foo" | sudo -u otheruser bash
# $./test.sh
# hello from otheruser

5

설명하는 방식이 아닌 함수를 내보낼 수 없습니다. 쉘은 ~/.bashrc대화식 쉘의 시작시 에만 파일을 로드합니다 ( bash 맨 페이지 에서 "Invocation"검색 ).

프로그램을 시작할 때로드되는 "라이브러리"를 작성하면됩니다.

source "$HOME/lib/somefile"

비 대화식 기능 및 설정을 여기에 배치하십시오.


따라서 "login"매개 변수를 사용하여 서브 쉘을 시작하거나 (~ / .profile 구문 분석) 해당 파일을 소싱해야합니다.
Nils

비 대화식 쉘에서 좀 더 자세히 살펴보면 이미 가지고있는 BASH_ENV환경 변수를 설정할 수 some_file있으며 호출됩니다. 그것을 알기에 충분히 쉬울 것이다 :echo echo foobar > /tmp/foobar; BASH_ENV=/tmp/foobar $SHELL -c :
Arcege

2

eval "$(declare -F | sed -e 's/-f /-fx /')"모든 기능 을 내 보냅니다 .

함수와 변수를 사용하는 동안 스크립트 컨텍스트에서 디버깅하고 작업 할 수 있도록 스크립트에서 대화식 셸을 시작하기 전에이 작업을 많이 수행합니다.

예:

eval "$(declare -F | sed -e 's/-f /-fx /')"
export SOME IMPORTANT VARIABLES AND PASSWORDS
bash -i

1

함수는 서브 프로세스로 내보내지지 않습니다. 이것이 .kshrc 또는 .bashrc라는 파일이있는 이유입니다. 서브 쉘에서도 사용할 수있는 함수를 정의합니다.

스크립트를 실행하는 경우. * shrc 스크립트는 일반적으로 소스되지 않습니다. 에서처럼 명시 적으로 코딩해야 . ~/.kshrc합니다.


스크립트가 루트로 실행되기 때문에 ~ root / .bashrc가 옵션이 될 수 있습니다. 그 힌트에 감사드립니다.
Nils

. * shrc 파일을 사용하는 경우 대화 형 동작 (예 : 멍청한 별칭 rm=rm -i)을 강요하지
마십시오.

0

글쎄, 나는 리눅스를 처음 사용하지만 시도해 볼 수있다. 일부 파일에서는 'tmp / general'이라고 부르고 함수를 빌드합니다.

func1(){
   echo "func from general"
}

쉘 스크립트에서 다음을 추가하십시오.

. /tmp/general

다음을 실행하십시오.

func1

화면이 나타납니다 : func from general.


0
declare -x -f NAME

더 많은 정보

-f 조치 또는 기능 이름 및 정의로 표시 제한
-x를 사용하여 NAMEs 내보내기
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.