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

17

Eu uso o Bash como meu shell interativo e fiquei imaginando se havia uma maneira fácil de fazer com que o Bash execute 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 (s) processo (s) nomeado (s) em vez de enviar um sinal:

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

Sem especificar o caminho completo do comando do sistema, o Bash interno é usado em vez do comando do sistema. O killbuiltin não tem a -popção, portanto, o comando falha:

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

Tentei as respostas listadas em Faça com que o bash use o comando externo `time` em vez do shell interno, mas a maioria deles funciona apenas porque timeé na verdade uma palavra - chave shell - não um shell embutido .

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

$(which kill) -p httpd

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

Observe que killé apenas um exemplo e eu gostaria de uma solução generalizada semelhante à maneira como o prefixo com o commandbuiltin impede que funções com o mesmo nome de um comando externo sejam executadas. Na maioria dos casos, eu geralmente prefiro usar a versão embutida, pois economiza a bifurcação de um novo processo e, algumas vezes, o embutido possui recursos que o comando externo não possui.

Anthony G - justiça para Monica
fonte
A inclusão which killde backticks (não é possível colocá-los nos comentários) é um pouco menor.
abligh
Bom ponto. Passei anos treinando-me a usar o "novo" sintaxe er para substituição de comando :).
Anthony G - justiça para Monica
@abligh: Para sua informação, você pode colocar `backticks 'nos comentários precedendo-os com barras invertidas (\). Mas há razões para se manter $(…)- veja isto , isto e aquilo .
G-Man diz 'Reinstate Monica'

Respostas:

20

Assumindo que envestá no seu caminho:

env kill -p http

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

Isso produz algum cruft de controle de tarefa do shell, mas não depende de um comando externo:

exec kill -p bash &

execrequer 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 em segundo plano bifurcado, não o shell atual.

chepner
fonte
2
envé claramente a resposta certa IMHO.
abligh
@abligh: Você está certo em comentar minha resposta excluída. command -p cmdchamando comando externo zsh, não bash.
cuonglm
6
(exec kill -p http)faz com que o trabalho substitua um sub-shell em vez do seu shell atual e você não precisa lidar com o cruft de controle do trabalho.
Michael Hoffman
1
@AnthonyGeoghegan De fato, mas envtambém não sabe sobre os componentes internos do shell, já que não é um shell. Você deseja obter o mesmo efeito com niceou xargsou qualquer outro programa como esse.
user253751
1

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

alias kill="/bin/kill"

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

Benjamin Staton
fonte
Eu já tinha pensado em um alias e essa foi uma das soluções listadas na pergunta à qual vinculei, mas espero por uma solução mais generalizada (semelhante à commandsolução) em vez de criar um alias separado para cada comando "sombreado". Agora editei minha pergunta para tornar isso mais claro e explícito. Na maioria dos casos, geralmente prefiro usar a versão interna, pois os processos podem ser especificados por IDs de trabalho. Obrigado de qualquer maneira.
Anthony G - justiça para Monica
1

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

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

Abreviar coisas que normalmente exigem algum esforço é o que os computadores se destacam.

PSkocik
fonte
1
Esse é um bom ponto geral, por isso vou votar sua resposta. Nos últimos anos, criei uma coleção de aliases, funções e scripts para os sistemas que uso regularmente. No entanto, prefiro usar soluções não personalizadas sempre que possível, pois às vezes tenho que trabalhar em novas instalações ou servidores que não configurei. Obrigado.
Anthony G - justiça para Monica
1

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

Em um sentido geral, uma função funciona. Do "comando de arquivo":

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

chamar como

fcmd kill -p httpd

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

Do conceito "list pid" (lp):

alias lp='/bin/kill -p'

então, digite:

lp httpd

fonte
0

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

$ =kill -p httpd
Caleb
fonte
1
Eu tentei isso com o Bash versão 4.3.30 e não funcionou. Eu nunca vi essa sintaxe antes; você pode adicionar um link para onde esse recurso está documentado? Normalmente, prefixo um alias com uma barra invertida para executar a versão sem alias de um comando.
Anthony G - justiça para Monica
@ Anthony talvez isso seja uma zshúnica coisa. Uso-o regularmente, mas vou verificar a bashpartir de um computador amanhã.
Caleb
Eu suspeitava que poderia ser algum shell com o qual não estou familiarizado (estou familiarizado apenas com o bash, dash e csh). Houve outra resposta (desde que excluída) que apenas funcionou zsh. Enquanto eu marquei esta questão bashe a usei no título, você deve manter essa resposta, pois um usuário do zsh ainda a achará útil.
Anthony G - justiça para Monica
-1

Você pode enviar um relatório de erros em sua página de killmanual e perguntar por que isso inclui opções não padrão que são retiradas pkille usadas pkillsempre que você deseja obter os recursos.pkill.

Se você ligar para:

pkill httpd

você evita os problemas que você descreve.

esperto
fonte