lire avec l'histoire

11

Comment puis-je faire l'historique de readprise en charge de la commande intégrée , en appuyant sur la touche haut / bas pour les parcourir?

J'ai essayé d'attraper lorsque vous appuyez sur la touche haut, mais cela ne semble pas fonctionner avec read:

read -p '> ' -n 3 foo
echo
echo -n "$foo" | hexdump

Appuyer sur les touches fléchées semble fonctionner et je peux le détecter en utilisant cela, mais si j'appuie aa, il échouera car il ne lira que le premier caractère de l'identifiant de la flèche vers le haut, tandis que le troisième est nécessaire pour distinguer les différentes flèches clés.

Tyilo
la source

Réponses:

9

Vous pouvez l'utiliser rlwrappour cela, si cela ne vous dérange pas d'installer un logiciel.

Vous voudrez probablement garder un fichier historique séparé qui ne conserve que l'historique de l'invite particulière dans votre script (c'est-à-dire éviter de mélanger avec l'historique des commandes shell de l'utilisateur).

Voici un exemple qui pourrait vous convenir:

#!/bin/sh
# Save in rlwrap_example.sh

HISTORY=$HOME/.myscript_history
USERINPUT=$(rlwrap -H $HISTORY sh -c 'read REPLY && echo $REPLY')
echo "User said $USERINPUT"

$ ./rlwrap_example.sh
hello
User said hello

Dans le script ci-dessus, l'utilisateur peut utiliser toutes les fonctionnalités de lecture en ligne GNU , avec l'historique servi depuis - et stocké dans -  ~/.myscript_history. Ajustez au besoin.

Alternativement, vous pouvez utiliser bash read -e, qui active readline pour les readappels, mais vous trouverez probablement sa fonctionnalité d'historique trop limitée (c'est-à-dire presque inexistante).

mrb
la source
10

Pour copier l'excellente réponse de Mike Stroyan à partir de cet ancien message de la liste de diffusion :

Vous pouvez utiliser "history -r" pour lire un fichier dans l'historique du shell et "history -s" pour ajouter chaque ligne que vous lisez dans l'historique. Utilisez ensuite history -w pour sauvegarder l'historique dans le fichier. Voici un exemple d'édition de ligne de lecture de style vi.

#!/bin/bash
history -r script_history
set -o vi
CMD=""
while true
do
    echo "Type something"
    read -e CMD
    history -s "$CMD"
    echo "You typed $CMD"
    case "$CMD" in
        stop)
            break
            ;;
        history)
            history
            ;;
    esac
done
history -w script_history
echo stopping
Chris Pacejo
la source
J'aime mieux cette solution rlwrapcar (au moins sur ma machine) rlwrapest incapable de gérer CTRL-C avec élégance, par exemple essayez d'exécuter USERINPUT=$(rlwrap -o cat)et d'appuyer sur CTRL-C et voyez comment votre terminal se comporte ensuite (exécutez la resetcommande pour revenir à un état sain) .
zpon
Cela fonctionne très bien si vous ne souhaitez pas installer de bibliothèques supplémentaires et que vous êtes satisfait d'utiliser un fichier séparé pour gérer les entrées.
Luke Exton