Sim, e isso fica mais claro quando você considera o que realmente é uma função de shell.
Para shells compatíveis com POSIX, uma definição de função é padronizada da seguinte forma:
E assim, em sua essência, uma função de shell chamada fname
é uma cadeia literal composta de pelo menos um comando composto que o shell chamará da memória e executará no lugar de fname
quando ocorre na entrada na posição do comando - o que significa que qualquer cmd irá fazer. Esta definição abre muitas possibilidades para o uso de uma função em um shell POSIX. Qualquer um dos itens a seguir é aceitável:
fn() {
command; list;
fn() { : redefines itself upon first execution; }
}
... e ...
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
}
Mas esse é um pequeno exemplo. Se você considerar o significado de comando composto , poderá começar a ver que a forma convencional fn() { : cmds; }
é apenas um caminho em que uma função pode funcionar. Considere alguns tipos diferentes de comandos compostos:
{ 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
E outros além disso. Qualquer uma das opções acima deve funcionar como ...
fname() compound list
... e dentre aqueles que podem ser aninhados quando não atribuídos como uma função, ainda podem ser aninhados, mesmo se definidos como um comando.
Aqui está uma maneira de escrever sua função:
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 '3%s' \[A @
)
PROMPT
Algumas notas sobre o que precede:
- O
read
na atualização está sujeito à interpretação do IFS e da contrabarra. Robustamente, poderia ser IFS= read -r "$1"
, mas não tenho certeza de como você deseja que essas coisas sejam interpretadas. Procure outras respostas neste site para obter mais e melhores informações sobre essa pontuação.
- O
printf '3%s...
no aqui-doc supõe que /dev/tty
esteja vinculado a um terminal compatível com VT100 e, nesse caso, as fugas usadas devem impedir que a nova linha final do here-doc seja exibida na tela. Robustamente tput
seria usado. do man termcap
para mais informações.
- O melhor é que a suposição da VT100 esteja correta e você pode fazer sem
printf
ou tput
inserindo os caracteres de escape literalmente no documento here como ^V{esc}[A^V{esc}@
em que ^V
é uma maneira de representar o CONTROL+V
combinação de teclas e {esc}
é a chave ESC
do seu teclado.
A função acima irá puxar em dobro, dependendo do seu conjunto de parâmetros - ele será executado duas vezes e reavaliar o prompt somente quando necessário - e, portanto, não precisa de uma segunda função - porque ele pode fazer as duas coisas, desde que é inicialmente chamado sem parâmetros em primeiro lugar.
Então, se eu correr ...
update_prof; printf %s\n "$name"
A atividade do terminal resultante é semelhante:
1. Update Name
2. Update Age
3. Update Gender
Enter option: 1
Enter name: yo mama
yo mama