Use o comando do sistema em vez do Bash incorporado sem especificar o caminho completo

17

Eu uso o Bash como meu shell interativo e fiquei me perguntando se havia uma maneira fácil de fazer o Bash executar um comando do sistema em vez de um comando interno do shell no caso em que ambos compartilham o mesmo nome.

Por exemplo, use o sistema kill (de util-linux ) para imprimir o ID do processo (pid) do processo nomeado em vez de enviar um sinal:

$ /bin/kill -p httpd
2617
...

Sem especificar o caminho completo do comando do sistema, o Bash builtin é usado no lugar do comando do sistema. O kill incorporado não tem a opção -p , por isso o comando falha:

$ kill -p httpd
bash: kill: p: invalid signal specification

Eu tentei as respostas listadas em Fazer o bash usar o comando externo 'time' em vez de shell embutido mas a maioria deles só funciona porque time é na verdade uma shell keyword - não um shell embutido .

Além de desativar temporariamente o Bash incorporado com enable -n kill , a melhor solução que vi até agora é usar:

$(which kill) -p httpd

Existem outras maneiras mais fáceis (envolver menos digitação) para executar um comando externo em vez de um shell embutido?

Observe que kill é apenas um exemplo e gostaria de uma solução generalizada semelhante à maneira como o prefixo com o command interno impede funções que tenham o mesmo nome de um comando externo de ser executado. Na maioria dos casos, geralmente prefiro usar a versão incorporada, já que economiza um novo processo e, algumas vezes, o builtin tem recursos que o comando externo não faz.

    
por Anthony Geoghegan 12.11.2015 / 12:57

6 respostas

20

Assumindo que env esteja em seu caminho:

env kill -p http

env executa o arquivo executável nomeado por seu primeiro argumento em um ambiente (possivelmente) modificado; como tal, ele não conhece ou trabalha com comandos internos do shell.

Isso produz alguma restrição de controle de tarefa do shell, mas não depende de um comando externo:

exec kill -p bash &

exec requer um executável para substituir o shell atual, portanto, não usa nenhum built-in. O trabalho é executado em segundo plano para que você substitua o shell de segundo plano bifurcado, não seu shell atual.

    
por 12.11.2015 / 15:35
1

A maneira mais simples de fazer o que você quer é colocar a linha

alias kill="/bin/kill"

no seu arquivo ~/.bashrc . Depois disso, cada novo login / invocação do bash interpretará "kill" como /bin/kill .

    
por 12.11.2015 / 13:29
1

Se você conhece uma solução que requer alguma digitação e deseja uma solução que requeira menos digitação, crie-a:

runFile() { local cmd="$1"; shift; cmd="$(which "$cmd")" && "$cmd" "$@"; }

Abreviar as coisas que normalmente exigem algum esforço é o que os computadores são excelentes.

    
por 12.11.2015 / 21:15
1

Neste caso muito específico, o comando pgrep é uma correspondência exata para a necessidade.

De um modo geral, uma função funciona. De "comando de arquivo":

fcmd(){ local a=$1; shift; $(which "$a") "$@"; }

ligar como

fcmd kill -p httpd

Mas se você precisar de menos digitação, não há um caminho mais curto do que um bom alias.

A partir do conceito "list pid" (lp):

alias lp='/bin/kill -p'

depois, basta digitar:

lp httpd
    
por 13.11.2015 / 19:51
0

(em zsh) Você pode prefixar qualquer nome de comando com um sinal = para obter a versão do sistema em vez de um embutido. Essa também é uma maneira útil de evitar os aliases que atrapalham um cenário específico.

$ =kill -p httpd
    
por 12.11.2015 / 21:06
-1

Você pode enviar um bugreport sobre sua kill manpage e perguntar por que isso inclui opções não padrão obtidas de pkill e usar pkill sempre que você quiser obter os recursos em pkill.

Se você ligar:

pkill httpd

você evita os problemas que descreve.

    
por 28.01.2016 / 15:46