Você pode executar uma função Bash com o comando 'at'?

5

Eu quero executar uma função Bash em um horário agendado. Eu acho que a ferramenta certa para isso é o comando at .

No entanto, não parece estar funcionando.

function stupid () {
    date
}

export -f stupid

cat << EOM | at now + 1 minute
stupid
EOM

Depois de esperar o minuto, eu verifico meu e-mail e este é o erro que vejo:

sh: line 41: syntax error near unexpected token '=\(\)\ {\ \ date"
"}'
sh: line 41: '"}; export BASH_FUNC_stupid()'

Eu não entendo o que está errado aqui, especialmente porque sei que a função funciona.

$ stupid
Fri May 29 21:05:38 UTC 2015

Olhando para o erro, acho que o shell incorreto está sendo usado para executar a função ( sh em oposição a bash ), mas se eu verificar $SHELL , vejo que aponta para /bin/bash , e página man para at diz:

$ echo $SHELL
/bin/bash
$ man at

    ...

    SHELL   The value of the SHELL environment variable at the time
           of at invocation will determine which shell is used  to
           execute  the at job commands.

Então Bash deve ser o shell executando minha função.

O que está acontecendo aqui? Existe uma maneira de executar minha função Bash com at ?

    
por Nick Chammas 29.05.2015 / 23:12

2 respostas

10

As funções de bash são exportadas pelo ambiente. O comando at disponibiliza o ambiente, o umask e o diretório atual do processo de chamada para o script, gerando código shell que reproduz o ambiente. O script executado pelo seu trabalho é algo assim:

#!/bin/bash
umask 022
cd /home/nick
PATH=/usr/local/bin:/usr/bin:/bin; export PATH
HOME=/home/nick; export HOME
…
stupid

Em versões mais antigas do bash, as funções eram exportadas como uma variável com o nome da função e um valor começando com () e consistindo em código para definir a função, por exemplo,

stupid="() {
    date
}"; export stupid

Isso tornou muitos cenários vulneráveis a uma falha de segurança, o bug ShellShock (encontrado por Stéphane Chazelas ), que permitia a qualquer um capaz de injetar o conteúdo de uma variável de ambiente sob qualquer nome para executar código arbitrário em um script bash. As versões do bash onde com uma correção do Shellshock usam uma maneira diferente: elas armazenam a definição da função em uma variável cujo nome contém caracteres que não são encontrados em variáveis de ambiente e que as shells não analisam como atribuições.

BASH_FUNC_stupid%%="() {
    date
}"; export stupid

Devido a % , esta não é uma sintaxe sh válida, nem mesmo no bash, portanto, a tarefa at falha, mesmo se tentar usar a função ou não. A versão Debian do , que é usada em muitas distribuições Linux, era changed na versão 3.16 para exportar apenas variáveis que possuam nomes válidos em shell scripts. Portanto, versões mais novas do at não passam funções exportadas pelo shell do Shell, enquanto as mais antigas são erradas.

Mesmo com versões do bash pré-Shellshock, a função exportada só funciona em scripts bash iniciados a partir da tarefa at, não no próprio job. No job em si, mesmo que seja executado por bash, stupid é apenas outra variável de ambiente; O bash só importa funções quando é iniciado.

Para exportar funções para um trabalho no, independentemente do bash ou na versão, coloque-os em um arquivo e forneça esse arquivo a partir do seu trabalho ou inclua-os diretamente em seu trabalho. Para imprimir todas as funções definidas em um formato que possa ser lido, use declare -f .

{ declare -f; cat << EOM; } | at now + 1 minute
stupid
EOM
    
por 30.05.2015 / 01:35
0

Bem, você já sabe que recebe correspondência. Isso é muito legal, porque você definitivamente pode executar uma função bash quando o e-mail chega.

Isso é de man bash :

  • $MAILPATH

    • Uma lista de nomes de arquivos separados por dois pontos, a serem verificados para correspondência. A mensagem a ser impressa quando o correio chegar em um determinado arquivo pode ser especificada separando o nome do arquivo da mensagem com um ? . Quando usado no texto da mensagem, $_ se expande para o nome do arquivo de mensagens atual. Exemplo:

      MAILPATH='/var/mail/bfox?"You have mail":~/shell-mail?"$_ has mail!"'
      
    • bash fornece um valor padrão para essa variável, mas a localização dos arquivos de mensagens do usuário que ela usa depende do sistema (por exemplo, /var/mail/$USER ) .

A propósito, $_ não é a expansão somente que pode ocorrer nesse contexto - você pode expandir praticamente qualquer coisa, para incluir substituições de comandos. Na verdade, você não precisa necessariamente imprimir nada. E os arquivos não necessariamente precisam conter mail - o shell tentará notificar quando uma verificação realizada a cada $MAILCHECK segundos indicar que um arquivo foi modificado desde a última vez que foi visto.

Ainda assim, a forma como os shells lidam com $MAILxxxx é geralmente dependente de prompts - o que quer dizer que, independentemente do valor de $MAILCHECK , se você não puxar um novo prompt no momento certo, você não recebe notificado - e não vai até você acionar o próximo prompt. Não tenho certeza sobre isso, mas talvez set -b possa afetar isso.

De qualquer forma, há mais de uma maneira de fazer esse tipo de coisa. Talvez o mais óbvio seria usar um sinal - agendar um trabalho at como:

echo kill -USR1 "$$" | at now + 1 minute
trap some_func USR1

E veja o que acontece.

    
por 30.05.2015 / 07:50