leer con historia

11

¿Cómo puedo hacer que el readcomando incorporado soporte el historial, presionando la tecla arriba / abajo para recorrerlos?

He intentado atrapar cuando presionas la tecla arriba, sin embargo, no parece funcionar con read:

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

Al presionar las teclas de flecha parece funcionar y puedo detectarlo usando esto, sin embargo, si presiono aa, fallará, ya que solo leerá el primer carácter del identificador de la flecha hacia arriba, mientras que el tercero es necesario para distinguir la flecha diferente llaves.

Tyilo
fuente

Respuestas:

8

Puede usarlo rlwrappara esto, si no le importa instalar software.

Probablemente desee mantener un archivo de historial separado que solo mantenga el historial de la solicitud particular en su script (es decir, evite mezclarlo con el historial de comandos de shell del usuario).

Aquí hay un ejemplo que podría funcionar para usted:

#!/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

En el script anterior, el usuario puede usar toda la funcionalidad de línea de lectura de GNU , con el historial servido desde - y almacenado en -  ~/.myscript_history. Ajustar según sea necesario.

Alternativamente, puede usar bash read -e, que habilita la línea de lectura para readinvocaciones, pero probablemente encontrará que su funcionalidad de historial es demasiado limitada (es decir, casi inexistente).

mrb
fuente
10

Para copiar la excelente respuesta de Mike Stroyan de esta vieja publicación de la lista de correo :

Puede usar "history -r" para leer un archivo en el historial del shell e "history -s" para agregar cada línea que lea en el historial. Luego use history -w para guardar el historial nuevamente en el archivo. Aquí hay un ejemplo con la edición de líneas de lectura de estilo 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
fuente
Me gusta esta solución mejor que rlwrapcuando (al menos en mi máquina) rlwrapno puede manejar CTRL-C con gracia, por ejemplo, intente ejecutar USERINPUT=$(rlwrap -o cat)y presionar CTRL-C y ver cómo se comporta su terminal después (ejecute el resetcomando para volver a un estado sano nuevamente) .
zpon
Esto funciona muy bien si no desea instalar libs adicionales y está contento de usar un archivo separado para administrar la entrada.
Luke Exton