Est-ce possible dans un bash interactif shell pour entrer une commande qui affiche du texte afin qu'il apparaisse à l'invite de commande suivante, comme si l'utilisateur avait tapé ce texte à cette invite ?
Je veux pouvoir source
un script qui générera une ligne de commande et l'affichera de sorte qu'il apparaisse lorsque l'invite revient après la fin du script afin que l'utilisateur puisse éventuellement le modifier avant d'appuyer sur enter
pour l'exécuter.
Ceci peut être réalisé avec xdotool
mais cela ne fonctionne que lorsque le terminal est dans une fenêtre X et uniquement s'il est installé.
[[email protected]] 100 $ xdotool type "ls -l"
[[email protected]] 101 $ ls -l <--- cursor appears here!
Cela peut-il être fait en utilisant bash uniquement ?
Réponse acceptée :
Avec zsh
, vous pouvez utiliser print -z
pour placer du texte dans le tampon de l'éditeur de ligne pour la prochaine invite :
print -z echo test
amorcerait l'éditeur de ligne avec echo test
que vous pourrez modifier à l'invite suivante.
Je ne pense pas que bash
a une fonctionnalité similaire, mais sur de nombreux systèmes, vous pouvez amorcer le tampon d'entrée du terminal avec le TIOCSTI
ioctl()
:
perl -e 'require "sys/ioctl.ph"; ioctl(STDIN, &TIOCSTI, $_)
for split "", join " ", @ARGV' echo test
Insèrerait echo test
dans le tampon d'entrée du terminal, comme s'il était reçu du terminal.
Une variante plus portable de la Terminology
de @mike approche et qui ne sacrifie pas la sécurité serait d'envoyer à l'émulateur de terminal un query status report
assez standard séquence d'échappement :<ESC>[5n
quels terminaux répondent invariablement (donc en entrée) comme <ESC>[0n
et liez-le à la chaîne que vous souhaitez insérer :
bind '"e[0n": "echo test"'; printf 'e[5n'
Si dans l'screen
GNU , vous pouvez également faire :
screen -X stuff 'echo test'
Maintenant, à l'exception de l'approche TIOCSTI ioctl, nous demandons à l'émulateur de terminal de nous envoyer une chaîne comme si elle était tapée. Si cette chaîne vient avant readline
(bash
l'éditeur de ligne) a désactivé l'écho local du terminal, alors cette chaîne sera affichée pas à l'invite du shell, gâchant légèrement l'affichage.
Pour contourner ce problème, vous pouvez soit retarder légèrement l'envoi de la requête au terminal pour vous assurer que la réponse arrive lorsque l'écho a été désactivé par readline.
bind '"e[0n": "echo test"'; ((sleep 0.05; printf 'e[5n') &)
(ici en supposant que vous sleep
prend en charge une résolution inférieure à la seconde).
Idéalement, vous voudriez faire quelque chose comme :
bind '"e[0n": "echo test"'
stty -echo
printf 'e[5n'
wait-until-the-response-arrives
stty echo
Cependant bash
(contrairement à zsh
) n'a pas de support pour un tel wait-until-the-response-arrives
qui ne lit pas la réponse.
Cependant, il a un has-the-response-arrived-yet
fonctionnalité avec read -t0
:
bind '"e[0n": "echo test"'
saved_settings=$(stty -g)
stty -echo -icanon min 1 time 0
printf 'e[5n'
until read -t0; do
sleep 0.02
done
stty "$saved_settings"
Autres lectures
Voir la réponse de @starfry qui développe les deux solutions données par @mikeserv et moi-même avec quelques informations plus détaillées.