함수 내에 함수를 추가하는 것이 가능한가요?

함수 내에 함수를 추가하는 것이 가능한가요?

이것은 내 코드입니다.

function update_profile
{
    echo "1. Update Name"
    echo "2. Update Age"
    echo "3. Update Gender"
    echo "Enter option: "
    read option

    case $option in
         1) update_name ;;
         2) update_age ;;
         3) update_gender ;;
    esac

    function update_name
    {
        echo "Enter new name: "
        read name
    }
}

이것이 가능한지 확인하고 싶었습니다. 모든 코드를 케이스에 넣을 수 있다는 것은 알고 있지만 그렇게 하면 지저분해지기 때문에 함수 내부에 독립형 함수를 만들고 해당 명령을 실행해야 할 때마다 호출하고 싶습니다.

답변1

예, 가능합니다.

그다지 유용하지는 않지만 다른 함수 내에 함수를 중첩하는 것도 가능합니다.

f1 ()
{

  f2 () # nested
  {
    echo "Function \"f2\", inside \"f1\"."
  }

}  

f2  #  Gives an error message.
    #  Even a preceding "declare -f f2" wouldn't help.

echo    

f1  #  Does nothing, since calling "f1" does not automatically call "f2".
f2  #  Now, it's all right to call "f2",
    #+ since its definition has been made visible by calling "f1".

    # Thanks, S.C.

원천:Linux 문서화 프로젝트

답변2

함수 내를 포함하여 셸에서 명령이 필요한 모든 위치에서 함수를 정의할 수 있습니다. 이 함수는 쉘이 파일을 구문 분석할 때가 아니라 쉘이 해당 정의를 실행할 때 정의된다는 점에 유의하십시오. 따라서 사용자가 처음 실행할 때 옵션 1을 선택하면 when 문이 호출될 때 함수 정의가 실행되지 않았기 update_profile때문에 코드가 작동하지 않습니다 . 함수가 한 번 실행되면 함수 도 정의됩니다.update_namecaseupdate_nameupdate_profileupdate_name

update_name의 정의를 사용되는 위치 앞으로 이동해야 합니다 .

update_name내부를 정의하는 것은 update_profile특별히 유용하지 않습니다. 이는 첫 번째 실행 update_name까지는 정의되지 않지만 그 이후에는 계속 사용할 수 있음을 의미합니다. 내부적으로만 사용할 수 있도록 update_profile하려면 함수를 정의하고 함수에서 반환되기 전에 호출하세요. 그럼에도 불구하고 간단한 작업을 수행하고 모든 기능을 전역적으로 정의하는 것과 비교하면 실제로 아무 것도 얻지 못합니다.update_nameupdate_profileunset -f update_name

답변3

예, 이는 실제로 쉘 기능이 무엇인지 고려하면 더욱 명확해집니다.

POSIX 호환 셸의 경우 함수 정의가 표준화됩니다.

  • 2.9.5기능 정의 명령

    • 기능다음과 같이 사용되는 사용자 정의 이름입니다.간단한 명령부르다복합 명령새로운위치 매개변수. 기능이 사용됩니다 "기능 정의 명령"...다음과 같이:

    fname() compound-command[io-redirect ...]

    • 함수 이름은 fname... 구현은 별도의 네임스페이스를 유지해야 합니다.기능그리고변하기 쉬운.

    • 논쟁복합 명령을 나타냅니다복합 명령에 설명된 대로복합 명령.

      • 언제. . . 언제기능발표되었는데 하나도 아니고확장하다존재하다단어 확장기반으로해야합니다compound-command또는<<&io-redirect&>;이 함수가 호출될 때마다 모든 것이 ${expansions}정상적으로 실행되어야 합니다. 마찬가지로 선택사항<<&io-redirect&>리디렉션 및 기타variable=assignments이내에compound-command함수 정의 중이 아닌 함수 자체 실행 중에 실행되어야 합니다. 바라보다쉘 오류의 결과대화형 및 비대화형 쉘에서 이러한 작업이 실패하면 결과가 나타납니다.

따라서 본질적으로 name이라는 쉘 함수는 fname최소한 하나의 문자열을 포함하는 리터럴 문자열입니다.복합 명령fname쉘은 입력에 나타나는 것이 아니라 메모리에서 호출되고 실행됩니다.명령 위치- 이 말은 언제든지지침할 것입니다. 이 정의는 POSIX 셸에서 함수를 사용할 수 있는 많은 가능성을 열어줍니다. 다음 상황 중 하나라도 허용됩니다.

fn() {
    command; list;
    fn() { : redefines itself upon first execution; }
}

...그리고...

fn() {
    helper1() { : defines another function which it can call; }
    helper2() { : and another; }
    helper1 "$@" | helper2 "$@"     #processes args twice over pipe
    command "$@"; list;             #without altering its args
}

그러나 이것은 단지 작은 예일 뿐입니다. 의미를 생각해 보면복합 명령당신은 전통적인 fn() { : cmds; }형태가 단지일방 통행기능이 작동합니다. 몇 가지 다른 유형의 복합 명령을 고려하십시오.

 { compound; list; of; commands;} <>i/o <i >o
 (subshelled; compound; list; of; commands) <>i/o <i >o
 if ...; then ...; fi <>i/o <i >o
 case ... in (...) ...;; esac <>i/o <i >o
 for ... [in ... ;] do ...; done <>i/o <i >o
 (while|until) ...; do ....; done <>i/o <i >o

그 외에도 다른 것들도 있습니다. 위의 내용 중 하나는 다음과 같습니다.

 fname() compound list

...그리고 함수로 할당되지 않았을 때 중첩될 수 있는 모든 항목은 명령으로 정의된 경우에도 여전히 중첩될 수 있습니다.

함수를 작성하는 한 가지 방법은 다음과 같습니다.

update_prof(){
    cat >&3
    read "${2-option}" <&3
    case "${1-$option}" in
    1) update_prof '' name      ;;
    2) update_prof '' age       ;;
    3) update_prof '' gender    ;;
    *) unset option             ;;
    esac
} <<-PROMPT 3<>/dev/tty
${1-
    1. Update Name
    2. Update Age
    3. Update Gender
}
    Enter ${2:-option}: $(
        printf '\033%s' \[A @
)
PROMPT

위에 대한 몇 가지 참고 사항:

  1. 업데이트에는 readIFS 및 백슬래시 해석이 적용됩니다. 아마도 사실일 것입니다. IFS= read -r "$1"하지만 이러한 내용을 어떻게 해석하고 싶은지 잘 모르겠습니다. 이 점수에 대한 더 많은 정보와 더 나은 정보를 얻으려면 이 사이트에서 다른 답변을 찾아보세요.
  2. 여기에 printf '\033%s...있는 문서의 가정은 /dev/ttyVT100 호환 터미널에 연결되며, 이 경우 사용된 이스케이프는 여기에 있는 문서의 마지막 개행 문자가 화면에 표시되지 않도록 해야 합니다. 튼튼하게 tput사용하겠습니다. 거기에서 man termcap더 많은 정보를 얻으세요.
    • 가장 좋은 것은 VT100입니다. 가 키 조합을 나타내는 방법 이고 가 키보드의 키인 것처럼 아무것도 사용하지 않거나 문서에 직접 이스케이프 문자를 입력할 printf수 있습니다 .tput^V{esc}[A^V{esc}@^VCONTROL+V{esc}ESC

위의 함수는 인수 집합에 따라 이중 임무를 수행합니다. 두 번 수행하고 필요한 경우에만 힌트를 재평가합니다. 따라서 두 번째 함수가 필요하지 않습니다. 처음에 호출되는 한 두 가지를 모두 수행할 수 있기 때문입니다. 먼저 매개변수가 없습니다.

그래서 내가 달리면...

update_prof; printf %s\\n "$name"

후속 터미널 활동은 다음과 같습니다.

1. Update Name
2. Update Age
3. Update Gender

Enter option: 1

Enter name: yo mama
yo mama

답변4

여기에 Jeff Schaller의 삭제된 답변을 다시 추가하여 유스 케이스가 존재함을 보여주는 답변이 있는지 확인하고 "별로 유용하지 않다"는 허용된 답변의 의미가 본질적으로 잘못되었음을 확인합니다.

여기 다시 있습니다(내 대답이 무엇을 의미하는지 보여주기 위해 수정되었습니다).

"매우 유용"하지 않나요? 나는 이것이 실제로 꽤 멋지다고 생각한다.

/에는 내 환경을 주어진 프로젝트로 초기화하는 bashrc프로젝트별 초기화 기능이 있습니다 .bash_aliases

그 전에는 모든 별칭과 함수를 전역적으로 정의했습니다(이와 같은 단축키 cdprojectname). modulename_build문제는 많은 프로젝트를 수행한 후에 이름 충돌을 피하기 위해 매우 긴 이름을 쉽게 사용할 수 있다는 것입니다.

그래서 제가 한 것은 cdprojectname( cdsd프로젝트와 마찬가지로 sd) 프로젝트 디렉토리로 이동할 뿐만 아니라 프로젝트에 관한 모든 개발 환경을 초기화하는 기능을 사용하는 것입니다.

제 생각에는 쉘 함수를 정의하는 함수를 만들 수 있다는 것이 정말 멋지다고 생각합니다. 내 별칭을 사용할 때 이것이 작동하는지 테스트해야 합니다.vim

  • 응 확인해 봤는데 내 트릭이 작동하지 않아
  • jaja 어쨌든, 지금 vim에서 발행하면 작동하지도 않습니다 cdsd. 여전히 멋진 기능입니다!

답변에 대한 의견은

“답변에 “감사합니다”를 추가하지 마십시오. 평판이 충분하면 도움이 된다고 생각하는 질문과 답변에 투표할 수 있습니다. – Jeff Schaller.

죄송합니다. 편지를 쓸 수는 없었지만 감사의 뜻으로 쓴 내용은 쓰지 않았습니다. 하지만 이전 댓글/답변을 보면 이 기능의 가능한 사용 사례를 실제로 강조하지 않았으며 일부 사람들에게는 심지어 다음과 같은 내용도 있습니다. "다른 함수 내에 함수를 중첩할 수도 있습니다.하지만 이는 별로 유용하지 않습니다."

감사 인사는 아니지만, 실제로는 "별로 유용하지 않습니다"가 아니라 다른 스크립팅/셸 언어에 좋은 "매우 유용하고 깔끔한 기능"이라는 점을 지적하고 싶었습니다. 실제로 가지고 싶다!

매우 유용하지 않기 때문에 답변을 게시했지만 현재 허용되는 답변은 이런 식으로 제안합니다...원하는 방식으로 편집하거나 그대로 두십시오. 그렇지 않으면 허용된 답변이라고 생각합니다. 오류 메시지/프롬프트가 있습니다.

관련 정보