caffeinate espera executar uma comando em um novo processo.
Para interpretar uma função zsh , você precisa de um comando zsh .
E você precisaria passar a definição dessa função (assim como outras funções que ela pode precisar) para ela, por exemplo com:
mysleep() {
sleep 2
}
caffeinate zsh -c "$(functions mysleep);mysleep"
functions mysleep despeja a definição da função mysleep que passamos para o novo zsh para interpretação antes de chamar a função, para que zsh invocado por caffeinate acabe interpretando:
mysleep() {
sleep 2
};mysleep
Se compararmos a bash :
mysleep() {
sleep 2
}
export -f mysleep
caffeinate bash -c "mysleep"
(que é 2 caracteres mais curto para digitar), bash fará:
execve("/path/to/caffeinate",
["caffeinate", "bash", "-c", "mysleep"],
["BASH_FUNC_mysleep%%=() { sleep 2\n}", rest-of-environment])
Enquanto com zsh , obtemos:
execve("/path/to/caffeinate",
["caffeinate", "zsh", "-c", "mysleep () {\n\tsleep 2\n};mysleep"],
[rest-of-environment])
Eu vejo várias vantagens dessa última abordagem:
- temos controle total: sabemos como passamos a definição da função, como ela está sendo usada. Há menos espaço para coisas desagradáveis como o tipo de shellshock aqui.
- como o nome da variável de ambiente bash que transporta a definição de função contém
%caracteres (e mesmo que não tenha, pense emsudopor exemplo), não temos garantia de quecaffeinateserá propagá-lo para o comandobashque ele executa. - se for propagado, porque a definição da função é armazenada em envp [] em vez de argv [], isso significa que polui o ambiente de todos os outros comandos executados nesse ambiente (incluindo
sleep, por exemplo, neste exemplo). - (menor), embora o código shell
bashseja menor, mais dados são transmitidos paraexecve(), de modo que contribui mais para o limite E2BIG dessa chamada de sistema.
Se você quiser usar o ambiente, ainda é possível fazer isso:
FUNCS=$(functions mysleep) caffeinate zsh -c '
eval "$FUNCS";mysleep'
No caso de caffeinate aqui, é onde precisamos apenas que caffeinate seja executado enquanto a função está em execução, não necessariamente para executar a função, podemos usar outras abordagens como:
mysleep | caffeinate cat
cat será executado enquanto mysleep for executado. mysleep ainda seria executado em um processo separado e isso afeta o stdout de mysleep .
mysleep 3> {fd}>(caffeinate cat)
resolveria os dois problemas.
Como acima, isso cria um canal entre mysleep e cat . Mas a extremidade de gravação do pipe agora está em um descritor de arquivo alocado recentemente acima de 10 (armazenado em $fd ) para o qual mysleep normalmente não grava. Portanto, cat não lerá nada, mas esperará até o final do arquivo no canal, o que só acontecerá quando mysleep (e todos os processos filhos que herdam esse fd) terminar.