Estoy intentando escribir un script simple que lea desde la entrada estándar, usando ;
un carácter como delimitador para terminar la línea de entrada y que permita al usuario editar la línea.
Aquí está mi script de prueba:
#!/bin/bash
while true; do
read -e -d ";" -t 180 -p "><> " srcCommand
if [ $? != 0 ]; then
echo "end;"
echo ""
exit 0
fi
case "$srcCommand" in
startApp)
echo "startApp command";;
stopApp)
echo "stopApp command";;
end)
echo ""
exit 0
;;
*)
echo "unknown command";;
esac
done
Esto funciona pero no imprime el delimitador ';' carbonizarse:
# bash test.sh
><> startApp
startApp command
><> stopApp
stopApp command
><> end
Si elimino la opción -e, se imprime ;
pero el usuario no puede corregir su error usando el carácter de retroceso y las cadenas repetidas están justo después del delimitador:
# bash test.sh
><> startApp;startApp command
><> stopApp;stopApp command
><> end;
¿Cómo puedo imprimir el carácter delimitador y permitir al usuario editar la línea mientras leo la entrada estándar?
Este es el comportamiento esperado:
# bash test.sh
><> startApp;
startApp command
><> stopApp;
stopApp command
><> end;
Gracias
Respuesta1
Yo usaría zsh
donde el editor de líneas tiene muchas más capacidades y es mucho más personalizable:
#! /bin/zsh -
insert-and-accept() {
zle self-insert
# RBUFFER= # to discard everything on the right
zle accept-line
}
zle -N insert-and-accept
bindkey ";" insert-and-accept
bindkey "^M" self-insert
vared -p "><> " -c srcCommand
Con bash-4.3
o superior, puedes hacer algo similar con un truco como:
# bind ; to ^Z^C (^Z, ^C otherwide bypass the key binding when entered
# on the keyboard). Redirect stderr to /dev/null to discard the
# useless warning
bind '";":"\32\3"' 2> /dev/null
# new widget that inserts ";" at the end of the buffer.
# If we did bind '";":";\3"', readline would loop indefinitely
add_semicolon() {
READLINE_LINE+=";"
((READLINE_POINT++))
}
# which we bind to ^Z
bind -x '"\32":add_semicolon' 2> /dev/null
# read until the ^C
read -e -d $'\3' -t 180 -p '><> ' srcCommand
Tenga en cuenta que en esa versión, ;
siempre se inserta al final del búfer de entrada, no en la posición actual del cursor. Cambie el add_semicolon
a:
add_semicolon() {
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT++};"
}
Si desea que se inserte en el cursor y se descarte todo lo que está a la derecha. O:
add_semicolon() {
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT};${READLINE_LINE:READLINE_POINT}"
READLINE_POINT=${#READLINE_LINE}
}
si desea insertarlo en el cursor pero desea conservar lo que está a la derecha como en el zsh
enfoque.
Si no desea el ;
in $srcCommand
, siempre puede eliminarlo después, srcCommand="${srcComman//;}"
por ejemplo, pero deberá insertarlo en el widget para que se muestre con zle
/ readline
.