Desativa uma bandeira de comando e recursão infinita

2

Como ele substitui meu histórico quando usado em vários terminais, desejo desativar a funcionalidade fc -W . Infelizmente, tenho o hábito de digitá-lo com frequência.

Acho que não é possível criar um alias, pois há um espaço em branco em fc -W .

Então, tentei criar uma função, algo assim:

# Make sure to never invoke fc -W
fc(){
    for x; do
        if [[ "${x}" == -W ]]; then
            echo "I'm sorry Dave. I'm afraid I can't do that."
            return
        fi
    done
    fc "${@}"
}

No entanto, agora a chamada fc "${@}" chama a si mesma e recebo uma recursão infinita. Normalmente, eu evitaria isso usando, por ex. /usr/bin/fc , em vez de fc , no entanto:

$ type fc
> fc is a shell builtin

Como posso evitar a recursão infinita neste caso? Ou existe uma maneira melhor de desativar um sinalizador de um comando?

    
por pfnuesel 02.03.2018 / 19:52

2 respostas

3

Use builtin :

builtin fc "$@"

Isso garantirá que o comando fc interno seja chamado.

Estilo: a mensagem de diagnóstico deve ir para o fluxo de erro padrão e a função deve retornar um status diferente de zero quando falhar:

echo 'Sorry, can not do that' >&2
return 1
    
por 02.03.2018 / 19:56
2

Você pode substituir um comando interno ou um comando externo ou uma função com um alias. Enquanto o alias estiver sendo executado, um alias com o mesmo nome não será expandido. Portanto, se a expansão do alias usar o nome do alias, isso chamará o comando interno ou externo ou a função do mesmo nome. Isso significa que você pode usar um alias de uma maneira simples para passar opções extras para um comando. Mas você não pode fazer muito mais, devido à maneira como a expansão de alias funciona - é uma simples substituição de palavras, sem avaliação.

Você pode substituir um comando interno ou um comando externo por uma função. O fato de uma função de certo nome estar atualmente em execução não afeta a execução e, em particular, não afeta o significado do nome da função: ela se refere à função. Funções recursivas não são comuns em programação shell, mas não há regras contra elas.

Em shells POSIX, você pode forçar um nome a se referir a um comando interno ou externo, colocando command antes da chamada. Em outras palavras, command ignora aliases e funções. Em zsh, command força uma chamada para um comando externo (a menos que a opção posix_builtins seja definida), ou seja, ela também ignora os recursos incorporados. Para forçar a execução de um zsh embutido, use o builtin builtin.

Isso leva a uma solução: na sua função de wrapper, chame builtin fc em vez de fc .

No entanto, essa não é necessariamente a melhor solução no seu caso, porque sua função será invocada em todos os lugares, incluindo chamadas para fc de outras funções. Quando você substituir o comportamento interno, recomendo que se atenha a um alias. Um alias só se aplica ao que você digita na linha de comando ou carrega com . (a.k.a. source ), não para funções carregadas com autoload -U (que é a maneira recomendada de carregar automaticamente uma função). Portanto, defina um fc alias que chame sua função de wrapper e dê à função wrapper um nome diferente.

fc_wrapper () {
    for x; do
        if [[ "${x}" == -*W* ]]; then
            echo >&2 "I'm sorry Dave. I'm afraid I can't do that."
            return 1
        fi
    done
    \fc "${@}"
}
alias fc=fc_wrapper

Eu coloquei \fc em vez de fc na definição da função. Isso não é necessário ao carregar a definição de .zshrc antes da definição do alias, mas é necessário, por exemplo, se você editar ou recarregar a definição de função durante a sessão interativa. Fiz algumas pequenas melhorias na função também:

  • Imprima a mensagem de erro no erro padrão.
  • Se você não estiver fazendo o trabalho, retorne um status de erro.
  • Também capture casos como fc -WI . Isso não é totalmente robusto, já que ele também captura uma chamada como fc -R -- -W (lendo o histórico de um arquivo chamado -W ), mas é bom o suficiente para este caso de uso.
por 02.03.2018 / 21:33