이것은 내 코드입니다.
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.
답변2
함수 내를 포함하여 셸에서 명령이 필요한 모든 위치에서 함수를 정의할 수 있습니다. 이 함수는 쉘이 파일을 구문 분석할 때가 아니라 쉘이 해당 정의를 실행할 때 정의된다는 점에 유의하십시오. 따라서 사용자가 처음 실행할 때 옵션 1을 선택하면 when 문이 호출될 때 함수 정의가 실행되지 않았기 update_profile
때문에 코드가 작동하지 않습니다 . 함수가 한 번 실행되면 함수 도 정의됩니다.update_name
case
update_name
update_profile
update_name
update_name
의 정의를 사용되는 위치 앞으로 이동해야 합니다 .
update_name
내부를 정의하는 것은 update_profile
특별히 유용하지 않습니다. 이는 첫 번째 실행 update_name
까지는 정의되지 않지만 그 이후에는 계속 사용할 수 있음을 의미합니다. 내부적으로만 사용할 수 있도록 update_profile
하려면 함수를 정의하고 함수에서 반환되기 전에 호출하세요. 그럼에도 불구하고 간단한 작업을 수행하고 모든 기능을 전역적으로 정의하는 것과 비교하면 실제로 아무 것도 얻지 못합니다.update_name
update_profile
unset -f update_name
답변3
예, 이는 실제로 쉘 기능이 무엇인지 고려하면 더욱 명확해집니다.
POSIX 호환 셸의 경우 함수 정의가 표준화됩니다.
2.9.5기능 정의 명령
- ㅏ기능다음과 같이 사용되는 사용자 정의 이름입니다.간단한 명령부르다복합 명령새로운위치 매개변수. 기능이 사용됩니다 "기능 정의 명령"...다음과 같이:
fname() compound-command[io-redirect ...]
함수 이름은
fname
... 구현은 별도의 네임스페이스를 유지해야 합니다.기능그리고변하기 쉬운.논쟁복합 명령을 나타냅니다복합 명령에 설명된 대로복합 명령.
따라서 본질적으로 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
위에 대한 몇 가지 참고 사항:
- 업데이트에는
read
IFS 및 백슬래시 해석이 적용됩니다. 아마도 사실일 것입니다.IFS= read -r "$1"
하지만 이러한 내용을 어떻게 해석하고 싶은지 잘 모르겠습니다. 이 점수에 대한 더 많은 정보와 더 나은 정보를 얻으려면 이 사이트에서 다른 답변을 찾아보세요. - 여기에
printf '\033%s...
있는 문서의 가정은/dev/tty
VT100 호환 터미널에 연결되며, 이 경우 사용된 이스케이프는 여기에 있는 문서의 마지막 개행 문자가 화면에 표시되지 않도록 해야 합니다. 튼튼하게tput
사용하겠습니다. 거기에서man termcap
더 많은 정보를 얻으세요.- 가장 좋은 것은 VT100입니다. 가 키 조합을 나타내는 방법 이고 가 키보드의 키인 것처럼 아무것도 사용하지 않거나 문서에 직접 이스케이프 문자를 입력할
printf
수 있습니다 .tput
^V{esc}[A^V{esc}@
^V
CONTROL+V
{esc}
ESC
- 가장 좋은 것은 VT100입니다. 가 키 조합을 나타내는 방법 이고 가 키보드의 키인 것처럼 아무것도 사용하지 않거나 문서에 직접 이스케이프 문자를 입력할
위의 함수는 인수 집합에 따라 이중 임무를 수행합니다. 두 번 수행하고 필요한 경우에만 힌트를 재평가합니다. 따라서 두 번째 함수가 필요하지 않습니다. 처음에 호출되는 한 두 가지를 모두 수행할 수 있기 때문입니다. 먼저 매개변수가 없습니다.
그래서 내가 달리면...
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.
죄송합니다. 편지를 쓸 수는 없었지만 감사의 뜻으로 쓴 내용은 쓰지 않았습니다. 하지만 이전 댓글/답변을 보면 이 기능의 가능한 사용 사례를 실제로 강조하지 않았으며 일부 사람들에게는 심지어 다음과 같은 내용도 있습니다. "다른 함수 내에 함수를 중첩할 수도 있습니다.하지만 이는 별로 유용하지 않습니다."
감사 인사는 아니지만, 실제로는 "별로 유용하지 않습니다"가 아니라 다른 스크립팅/셸 언어에 좋은 "매우 유용하고 깔끔한 기능"이라는 점을 지적하고 싶었습니다. 실제로 가지고 싶다!
매우 유용하지 않기 때문에 답변을 게시했지만 현재 허용되는 답변은 이런 식으로 제안합니다...원하는 방식으로 편집하거나 그대로 두십시오. 그렇지 않으면 허용된 답변이라고 생각합니다. 오류 메시지/프롬프트가 있습니다.