L'achèvement de Bash fait démarrer bash lentement

15

Le démarrage d'un bash sur mon système ubuntu prend environ 2 secondes. Si je supprime le chargement de / etc / bash_completition dans .bashrc, il démarre sans délai. Bien sûr, je ne veux pas abandonner la fin et je ne pense pas que le chargement de ce fichier soit une raison légitime pour un délai de 2 secondes.

Toutes les idées comment je peux découvrir quel est le problème ou comment je peux accélérer les choses.

user75250
la source
est-ce / bin / bash? - essayez / bin / dash pourrait être un peu plus rapide.
Sirex
3
C'est pourquoi j'ai désinstallé bash-complétement
Vi.

Réponses:

8

Mise à jour en 2013: la majeure partie de l'achèvement de bash a été réécrite pour terminer automatiquement le chargement uniquement en cas de besoin. Le script de base est désormais beaucoup plus léger.


Le script d'achèvement peut parfois être énorme dans les normes de script shell. Sur un serveur auquel j'ai accès, c'est presque 1700 lignes (57 Ko) et c'est juste le script principal . Dans /etc/bash_completion.dil y a ~ 200 scripts supplémentaires pour d'autres commandes ( openssl, mutt, mount...) pour un total 25537 lignes ou 1,2 MB. Chaque script, une fois obtenu, vérifie si une commande est réellement disponible avant de définir des gestionnaires d'achèvement; ~ 330 fois dans ce cas, chacun impliquant la vérification $PATHd'un fichier exécutable avec un nom donné. (Bien que je m'attende /usr/binà être mis en cache en mémoire ...)

Certes, même cela ne prend qu'une demi-seconde à charger, pas deux secondes complètes. Mais cela pourrait être au moins une partie du problème. Exécutez du -hs /etc/bash_completion*ou wc -l /etc/bash_completion{,.d/*} | grep totalsi vous voulez vérifier.


Vous pouvez essayer de sourcer manuellement le script, en mode "trace":

set -x
. /etc/bash_completion

Vous verrez chaque ligne au fur et à mesure de son exécution. S'il y a une commande particulière qui prend beaucoup de temps, vous devez la remarquer.

( set +xdésactive le mode trace.)

user1686
la source
Fonction de fluage même en mode texte simpliste? C'est plus probable que vous ne le pensez.
Vi.
@Vi: Après avoir vu zsh compiler ses scripts de démarrage en bytecode ...
user1686
1
Je vous remercie. C'était vraiment facile. Malheureusement, toutes les commandes n'étaient pas sensiblement différentes. Il semble donc que ce soit le montant massif qui cause le problème.
user75250
12

J'ai trouvé une solution un peu hack qui semble fonctionner assez bien.

Solution

Au bas de l' ~/.bashrcajout:

piège 'source / etc / bash_completion; piège USR1 'USR1
{sommeil 0,1; kill intégré -USR1 $$; } & renier

Explication

trap 'source /etc/bash_completion ; trap USR1' USR1

Configurez un gestionnaire à exécuter lorsque le shell reçoit le signal SIGUSR1; le gestionnaire chargera les complétions et donc il se désactivera.

{ sleep 0.1 ; builtin kill -USR1 $$ ; } & disown

Attendez un peu de manière asynchrone puis envoyez le signal au shell actuel. disownest nécessaire pour supprimer la bashrétroaction du contrôle de processus. sleepest nécessaire pour fonctionner de manière asynchrone.

Problèmes

Pour une raison quelconque, la première commande envoyée à ce shell ne sera pas enregistrée dans l'historique.

cYrus
la source
1
Cela ne semble pas donner un coup de pouce au démarrage - time bash -lc truerapporte ~ 0,12s avec ou sans cela, même si des time source /etc/bash_completionrapports plus élevés comme 0,26s. Cela a-t-il effectivement été corrigé ?
l0b0
Je ne sais pas si cela time bash -lc truefonctionne correctement ici depuis la truefin, ~0.1sdonc il ne source rien. Quoi qu'il en soit time source /etc/bash_completion, il y a ~ 0,17s ici et c'est à peu près le temps que je dois attendre pour PS1apparaître.
cYrus
2
Ingénieux! En explication, les commandes de piège manquent un USR1à la fin.
Fish Monitor
Avec SIGUSR, le gestionnaire de signal n'est invoqué qu'après avoir appuyé sur Entrée à l'invite du shell. Il y a une pause à ce moment pendant son exécution. Je suis passé à SIGQUIT et cela semble bien fonctionner.
Jon Nalley
5

Vous devez utiliser la dernière version (2.0) de bash_completion. Si vous utilisez Debian, il est dans Wheezy, mais il n'a aucune dépendance sur aucun autre paquet Wheezy, vous pouvez donc l'installer sur un squeeze sans problème.

La dernière version charge l'achèvement de manière dynamique à la volée, elle a donc divisé le temps de chargement rapide pour moi d'au moins 10 fois.

xryl669
la source
1

Vous pouvez utiliser un espace réservé pendant le chargement des finitions; cela devrait suffire à tromper vos yeux. Cela ne fonctionne évidemment que si le temps requis par source /etc/bash_completionest inférieur au temps dont vous avez besoin pour taper et émettre la première commande shell, sinon elle sera également retardée.

L'idée est de faire écho à un faux PS1, de se procurer les achèvements et enfin d'effacer le terminal.

Supposons que votre PS1est - \u@\h:\w\$ils que vous pourriez écrire quelque chose comme:

echo -ne "$USER@$HOSTNAME:${PWD/$HOME/\~}\$ "
source /etc/bash_completion
echo -ne '\e[2J\e[H'

Où:

  • 2J efface le terminal;
  • H déplacez le curseur dans le coin supérieur droit.

Remarque: vous souhaiterez peut-être vérifier si l'utilisateur est root et utiliser #au lieu de $pour des raisons de cohérence:

echo -ne "...$([ $UID = 0 ] && echo '#' || echo '$') "

Remarque: La suppression \e[2Jévite le scintillement, mais elle laissera des caractères indésirables si l'espace réservé est plus long que l'invite réelle.

cYrus
la source