I'm trying to write a simple script that read from standard input, using ;
character as delimiter to terminate the input line and that allows user to edit line.
Here is my test script:
#!/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
This works but doesn't print the delimiter ';' char:
# bash test.sh
><> startApp
startApp command
><> stopApp
stopApp command
><> end
If I remove -e option it prints out ;
but user can't correct his mistake using backspace character and echoed strings are just right after the delimiter:
# bash test.sh
><> startApp;startApp command
><> stopApp;stopApp command
><> end;
How can I print out the delimiter character and allow user to edit line while reading standard input?
This is the expected behavior:
# bash test.sh
><> startApp;
startApp command
><> stopApp;
stopApp command
><> end;
Thanks
I'd use zsh
where the line editor has many more capabilities and is a lot more customizable:
#! /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
With bash-4.3
or above, you can do something similar with a hack like:
# 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
Note that in that version, the ;
is always inserted at the end of the input buffer, not at the current cursor position. Change the add_semicolon
to:
add_semicolon() {
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT++};"
}
If you want it inserted at the cursor and everything on the right discarded. Or:
add_semicolon() {
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT};${READLINE_LINE:READLINE_POINT}"
READLINE_POINT=${#READLINE_LINE}
}
if you want to insert it at the cursor but want to preserve what's on the right like in the zsh
approach.
If you don't want the ;
in $srcCommand
, you can always strip it afterwards with srcCommand="${srcComman//;}"
for instance, but you'd need to insert it in the widget for it to be displayed by zle
/readline
.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다