Comment invoquer explicitement un shell intégré?

13

Je souhaite personnaliser la fonctionnalité de cdcommande selon mes besoins.

J'ai défini la fonction suivante - function cd () { cd "$@" && pushd "$@"; }

Le but de cette fonction est de pousser automatiquement le répertoire sur la pile afin qu'il me sauve l'effort de taper manuellement à pushd .chaque fois.

Cependant, la fonction ci-dessus est une fonction infiniment récursive, car l'appel à cdest interprété comme étant la fonction elle-même et non la fonction cdintégrée.

Comment puis-je référencer le cdintégré dans cette fonction?

Je sais que les alias peuvent être échappés en utilisant \. Comment échapper de manière plus explicite aux fonctions ou référencer des éléments intégrés?

Remarque: je ne veux pas renommer ma fonction en autre chose.

Kshitiz Sharma
la source
3
Pourquoi pas juste alias cd=pushd? À quoi vous attendez-vous lorsque vous enregistrez quelque chose qui n'est pas un chemin absolu (par exemple cd ../)?
Patrick
@Patrick pushdne prend pas en charge -P. Mais vous avez raison, comme le montre la question, cela function cdsemble un peu faux, car il a changé de répertoire deux fois.
Tino

Réponses:

5

Le commandbuiltin force un nom de commande à être interprété comme une commande intégrée ou externe (saut d'alias et recherche de fonction). Il est disponible dans tous les shells POSIX, y compris bash.

cd () { command cd "$@" && pushd "$@"; }

(Notez que cet exemple est mauvais: il ne fonctionne pas avec des chemins relatifs, et vous pourriez tout aussi bien taper pushden premier lieu.)

Dans bash et zsh (mais pas ksh), vous pouvez utiliser builtinpour forcer un nom de commande à être interprété comme une fonction intégrée, à l'exclusion des alias, des fonctions et des commandes externes.

Gilles 'SO- arrête d'être méchant'
la source
16

Bash a une commande (intégrée) builtin, qui fait exactement ce dont vous avez besoin. Remplacer cdpar builtin cddans votre fonction corrigera la récursivité.

Petr Uzel
la source
1

Je suppose que lorsque vous dites que vous "ne voulez pas renommer votre fonction en quoi que ce soit d'autre", vous voulez dire que vous voulez pouvoir appeler votre fonction du même nom que la commande d'origine.

Donc, une autre façon de faire cela qui fonctionne également pour les choses qui ne sont pas intégrées, est de nommer votre fonction autre chose, puis de définir un alias pour la commande encapsulée. Cela fonctionne car l'alias n'existe pas dans le contexte d'exécution de votre fonction.

Exemple wrapper.sh:

#!/bin/bash
function my_wrapper() { wrapped_program $@ && dostuff }

Et dans, par exemple, .bash_aliases:

source /path/to/wrapper.sh
alias wrapped_program="my_wrapper"

Mais c'est assez hacky. L'utilisation commandest préférable lorsque cela est possible.

matt2000
la source
-1

Pour que cela fonctionne avec des chemins relatifs, les éléments suivants seraient nécessaires:

function cd { 
   dir="$(realpath "$@")"
   command cd "$dir"
   pushd "$dir"
}

Cela suppose que vous êtes sur une distribution Linux suffisamment moderne qui contient l'utilitaire 'realpath'. (RHEL 6 ne le fait pas par exemple). Si Perl est disponible, 'realpath' peut être simulé en utilisant:

! realpath $(pwd) > /dev/null 2>&1  && function realpath {
    perl -e "use Cwd realpath; print realpath(\"$1\") . \"\\n\";"
}
Vinny
la source