Utilisez la commande système au lieu du Bash intégré sans spécifier le chemin complet

17

J'utilise Bash comme shell interactif et je me demandais s'il y avait un moyen facile de faire exécuter à Bash une commande système au lieu d'une commande intégrée au shell dans le cas où ils partagent tous les deux le même nom.

Par exemple, utilisez le système kill(from util-linux) pour imprimer l'ID de processus (pid) du ou des processus nommés au lieu d'envoyer un signal:

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

Sans spécifier le chemin complet de la commande système, la fonction intégrée Bash est utilisée à la place de la commande système. Le programme killintégré n'a pas l' -poption, donc la commande échoue:

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

J'ai essayé les réponses listées dans Make bash use external `time` command plutôt que shell built-in mais la plupart d'entre elles ne fonctionnent que parce qu'il times'agit en fait d'un mot clé shell - pas d'un shell intégré .

Outre la désactivation temporaire de la fonction intégrée de Bash enable -n kill, la meilleure solution que j'ai vue jusqu'à présent consiste à utiliser:

$(which kill) -p httpd

Existe-t-il d'autres moyens plus simples (impliquant moins de frappe) d'exécuter une commande externe au lieu d'un shell intégré?

Notez que ce killn'est qu'un exemple et j'aimerais une solution généralisée similaire à la façon dont le préfixe avec le commandcode intégré empêche les fonctions qui ont le même nom qu'une commande externe d'être exécutées. Dans la plupart des cas, je préfère généralement utiliser la version intégrée car elle évite de lancer un nouveau processus et, parfois, la fonction intégrée possède des fonctionnalités que la commande externe ne possède pas.

Anthony G - justice pour Monica
la source
La which killfermeture en guillemets (ne peut pas les mettre dans les commentaires) est légèrement plus courte.
abligh
@abligh Bon point. J'ai passé des années à m'entraîner à utiliser la "nouvelle" syntaxe er pour la substitution de commandes. :)
Anthony G - justice pour Monica
@abligh: Pour info, vous pouvez mettre des `backticks` dans les commentaires en les précédant de barres obliques inverses (\). Mais il y a des raisons de rester $(…)- voyez ceci , ceci et ceci .
G-Man dit `` Réintègre Monica '' le

Réponses:

20

En supposant que envvous êtes sur votre chemin:

env kill -p http

envexécute le fichier exécutable nommé par son premier argument dans un environnement (éventuellement) modifié; en tant que tel, il ne connaît pas ou ne fonctionne pas avec les commandes intégrées du shell.

Cela produit une perte de contrôle du travail shell, mais ne s'appuie pas sur une commande externe:

exec kill -p bash &

execnécessite un exécutable pour remplacer le shell actuel, donc n'utilise aucun module intégré. Le travail est exécuté en arrière-plan afin que vous remplaciez le shell d'arrière-plan fourchu, pas votre shell actuel.

chepner
la source
2
envest clairement la bonne réponse à mon humble avis.
abligh
@abligh: Vous avez raison en commentaire dans ma réponse supprimée. command -p cmdappeler une commande externe zsh, non bash.
cuonglm
6
(exec kill -p http)oblige le travail à remplacer un sous-shell au lieu de votre shell actuel et vous n'avez pas à gérer la perte de contrôle du travail.
Michael Hoffman,
1
@AnthonyGeoghegan En effet, mais envne sait pas non plus sur les commandes internes du shell, car ce n'est pas un shell. Vous obtiendriez le même effet avec niceou xargsou tout autre programme comme ça.
user253751
1

La façon la plus simple de faire ce que vous voulez pourrait être de mettre la ligne

alias kill="/bin/kill"

dans votre ~/.bashrcfichier. Après cela, chaque nouvelle connexion / invocation de bash interprétera "kill" comme /bin/kill.

Benjamin Staton
la source
J'avais déjà pensé à un alias et c'était l'une des solutions répertoriées dans la question à laquelle j'ai lié, mais j'espère une solution plus généralisée (similaire à la commandsolution) plutôt que de créer un alias distinct pour chaque commande "masquée". J'ai maintenant modifié ma question pour la rendre plus claire et plus explicite. Dans la plupart des cas, je préfère généralement utiliser la version intégrée car les processus peuvent être spécifiés par des ID de travail. Merci quand même.
Anthony G - justice pour Monica
1

Si vous connaissez une solution qui nécessite un peu de frappe et que vous voulez une solution qui nécessite moins de frappe, construisez-la:

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

Abréger des trucs qui prend normalement un peu d'effort est ce que les ordinateurs excellent.

PSkocik
la source
1
C'est un bon point général, je vais donc voter pour votre réponse. Au cours des dernières années, j'ai constitué une collection d'alias, de fonctions et de scripts pour les systèmes que j'utilise régulièrement. Cependant, je préfère utiliser des solutions non personnalisées dans la mesure du possible car je dois parfois travailler sur de nouvelles installations ou des serveurs que je n'ai pas configurés. Merci.
Anthony G - justice pour Monica
1

Dans ce cas très spécifique, la commande pgrepcorrespond exactement au besoin.

Dans un sens général, une fonction fonctionne. De la "commande de fichier":

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

appeler comme

fcmd kill -p httpd

Mais si vous avez besoin de moins de frappe, il n'y a pas de moyen plus court qu'un bon alias.

Du concept "list pid" (lp):

alias lp='/bin/kill -p'

puis, tapez simplement:

lp httpd

la source
0

(En zsh) Vous pouvez préfixer n'importe quel nom de commande avec un signe = pour obtenir la version du système au lieu d'une fonction intégrée. C'est également un moyen pratique d'esquiver les alias qui gâchent un scénario spécifique.

$ =kill -p httpd
Caleb
la source
1
J'ai essayé cela avec la version 4.3.30 de Bash et cela n'a pas fonctionné. Je n'ai jamais vu une telle syntaxe auparavant; pouvez-vous ajouter un lien vers où cette fonctionnalité est documentée? Je préfère normalement un alias avec une barre oblique inverse pour exécuter la version sans alias d'une commande.
Anthony G - justice pour Monica
@Anthony c'est peut-être une zshseule chose. Je l'utilise régulièrement mais je vérifierai à bashpartir d'un ordinateur demain.
Caleb
Je soupçonnais qu'il pourrait s'agir d'un shell que je ne connais pas (je ne connais que bash, dash et csh). Il y avait une autre réponse (supprimée depuis) ​​qui ne fonctionnait que pour zsh. Bien que j'aie marqué cette question avec bashet l' ai utilisée dans le titre, vous devriez garder cette réponse car un utilisateur zsh la trouverait toujours utile.
Anthony G - justice pour Monica
-1

Vous pouvez envoyer un rapport de bogue sur votre killpage de manuel et demander pourquoi cela inclut des options non standard qui sont extraites depkill et utilisées pkillchaque fois que vous voulez obtenir les fonctionnalités depkill.

Si vous appelez:

pkill httpd

vous évitez les problèmes que vous décrivez.

schily
la source