GNU/Linux >> Tutoriels Linux >  >> Linux

Bash peut-il écrire dans son propre flux d'entrée ?

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).

Connexes :Slash et antislash dans sed ?

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.


Linux
  1. Quel terminal est le meilleur :Bash vs Zsh

  2. Bash :Echo :Erreur d'écriture :Argument invalide ?

  3. Utilisation des déclarations de cas dans Bash

  4. Masquer l'entrée utilisateur sur le terminal dans le script Linux

  5. Instruction Bash/sh 'if else'

Comment écrire un script bash avec des exemples

Bash :Écrire dans un fichier

un programme peut-il lire sa propre section elf ?

Comment exécuter nohup et écrire son fichier pid dans une seule instruction bash

À quoi sert $# dans Bash

Comment puis-je convertir facilement des entités spéciales HTML à partir d'un flux d'entrée standard sous Linux ?