I read in the man
page, that you set readline parameters on an off or to a value by using
set var value
Is this the same as the set
builtin, and how do you set the variables once inputrc
has already been read and the shell is running?
bashreadline
I read in the man
page, that you set readline parameters on an off or to a value by using
set var value
Is this the same as the set
builtin, and how do you set the variables once inputrc
has already been read and the shell is running?
I believe what you are looking for is the bind
command itself. According to man builtin
information running bind <readline-command>
allows you to run one-offs, however, I couldn't get it to work like the manual says it should...it kept making keys not work for me; your mileage may vary. I did find the following commands which may be of use to you.
bind -p # Equivalent to dump-functions [machine readable]
bind -P # Equivalent to dump-functions [human readable]
bind -s # Equivalent to dump-macros [machine readable]
bind -S # Equivalent to dump-macros [human readable]
bind -v # Equivalent to dump-variables [machine readable]
bind -V # Equivalent to dump-variables [human readable]
Edit Note
I would like to point out how annoying it is that it doesn't work like the manual says it should because if you type in bind
and then press tab for auto-complete, it shows all of the commands.
The terminal driver does have line editing capabilities on most systems. You'll notice that you can use Backspace, Ctrl-U, sometimes Ctrl-W.
readline
is a GNU library maintained alongside bash
. There's nothing POSIX about it. POSIX defines an optional line editor (with vi
key binding) for sh
, but no provision to use it outside of sh
.
The ksh93
shell uses that vi
-style line editor (also supports emacs
or gmacs
-style) for its read
builtin when both stdin and stderr are a terminal and the corresponding option has been set: set -o emacs; IFS= read -r var
for instance for read
to use an emacs-style line-editor.
POSIX does specify the vi
editor though (optional), so you could invoke vi
to edit the content of a temporary file.
The zsh
equivalent of bash
's read -e
is vared
(a lot more advanced as it's using zsh
's zle (zsh line editor)).
In other shells, you can use some wrappers around readline or other line-editing libraries (like rlwrap
), or you can invoke bash -c 'read -e...'
or zsh -c 'vared...'
.
What you could also do is give the opportunity to the user to launch an editor.
Like:
if ! IFS= read -r var; then
if [ -n "$var" ]; then
tmp=$(create_tempfile) # create_tempfile left as an exercise
printf '%s\n' "$var" > "$tmp"
"${VISUAL:-${EDITOR:-vi}}" -- "$tmp"
var=$(cat < "$tmp")
rm -f -- "$tmp"
else
exit 1 # real EOF?
fi
fi
Then the user can press Ctrl-D twice to launch an editor on what he has already entered.
Otherwise, I once wrote that function that should work on most terminals on most Unices that implements a simple line editor.
LE() {
# shell Line Editor. Extremely slow and stupid code. However it
# should work on ansi/vt100/linux derived terminals on POSIX
# systems.
# Understands some emacs key bindings: CTRL-(A,B,D,E,F,H,K,L)
# plus the CTRL-W and CTRL-U normal killword and kill.
# no Meta-X key, but handling of <Left>, <Right>, <Home>, <End>
# <Suppr>.
#
# Args:
# [1]: prompt (\x sequences recognized, defaults to "")
# [2]: max input length (unlimited if < 0, (default))
# [3]: fill character when erasing (defaults to space)
# [4]: initial value.
# Returns:
# 0: OK
# 1: od(d) error or CTRL-C hit
LE_prompt=$1
LE_max=${2--1}
LE_fill=${3-" "}
LE_backward() {
LE_s=$1
while [ "x$LE_s" != x ]; do
printf '\b%s' "$2"
LE_s=${LE_s%?}
done
}
LE_fill() {
LE_s=$1
while [ "x$LE_s" != x ]; do
printf %s "$LE_fill"
LE_s=${LE_s%?}
done
}
LE_restore='stty "$LE_tty"
LC_COLLATE='${LC_COLLATE-"; unset LC_COLLATE"}
LE_ret=1 LE_tty=$(stty -g) LE_px=$4 LE_sx= LC_COLLATE=C
stty -icanon -echo -isig min 100 time 1 -istrip
printf '%b%s' "$LE_prompt" "$LE_px"
while set -- $(dd bs=100 count=1 2> /dev/null | od -vAn -to1); do
while [ "$#" -gt 0 ]; do
LE_k=$1
shift
if [ "$LE_k" = 033 ]; then
case "$1$2$3" in
133103*|117103*) shift 2; LE_k=006;;
133104*|117104*) shift 2; LE_k=002;;
133110*|117110*) shift 2; LE_k=001;;
133120*|117120*) shift 2; LE_k=004;;
133106*|117106*) shift 2; LE_k=005;;
133061176) shift 3; LE_k=001;;
133064176) shift 3; LE_k=005;;
133063176) shift 3; LE_k=004;;
133*|117*)
shift
while [ "0$1" -ge 060 ] && [ "0$1" -le 071 ] ||
[ "0$1" -eq 073 ]; do
shift
done;;
esac
fi
case $LE_k in
001) # ^A beginning of line
LE_backward "$LE_px"
LE_sx=$LE_px$LE_sx
LE_px=;;
002) # ^B backward
if [ "x$LE_px" = x ]; then
printf '\a'
else
printf '\b'
LE_tmp=${LE_px%?}
LE_sx=${LE_px#"$LE_tmp"}$LE_sx
LE_px=$LE_tmp
fi;;
003) # CTRL-C
break 2;;
004) # ^D del char
if [ "x$LE_sx" = x ]; then
printf '\a'
else
LE_sx=${LE_sx#?}
printf '%s\b' "$LE_sx$LE_fill"
LE_backward "$LE_sx"
fi;;
012|015) # NL or CR
LE_ret=0
break 2;;
005) # ^E end of line
printf %s "$LE_sx"
LE_px=$LE_px$LE_sx
LE_sx=;;
006) # ^F forward
if [ "x$LE_sx" = x ]; then
printf '\a'
else
LE_tmp=${LE_sx#?}
LE_px=$LE_px${LE_sx%"$LE_tmp"}
printf %s "${LE_sx%"$LE_tmp"}"
LE_sx=$LE_tmp
fi;;
010|177) # backspace or del
if [ "x$LE_px" = x ]; then
printf '\a'
else
printf '\b%s\b' "$LE_sx$LE_fill"
LE_backward "$LE_sx"
LE_px=${LE_px%?}
fi;;
013) # ^K kill to end of line
LE_fill "$LE_sx"
LE_backward "$LE_sx"
LE_sx=;;
014) # ^L redraw
printf '\r%b%s' "$LE_prompt" "$LE_px$LE_sx"
LE_backward "$LE_sx";;
025) # ^U kill line
LE_backward "$LE_px"
LE_fill "$LE_px$LE_sx"
LE_backward "$LE_px$LE_sx"
LE_px=
LE_sx=;;
027) # ^W kill word
if [ "x$LE_px" = x ]; then
printf '\a'
else
LE_tmp=${LE_px% *}
LE_backward "${LE_px#"$LE_tmp"}"
LE_fill "${LE_px#"$LE_tmp"}"
LE_backward "${LE_px#"$LE_tmp"}"
LE_px=$LE_tmp
fi;;
[02][4-7]?|[13]??) # 040 -> 177, 240 -> 377
# was assuming iso8859-x at the time
if [ "$LE_max" -ge 0 ] && LE_tmp=$LE_px$LE_sx \
&& [ "${#LE_tmp}" -eq "$LE_max" ]; then
printf '\a'
else
LE_px=$LE_px$(printf '%b' "\0$LE_k")
printf '%b%s' "\0$LE_k" "$LE_sx"
LE_backward "$LE_sx"
fi;;
*)
printf '\a';;
esac
done
done
eval "$LE_restore"
REPLY=$LE_px$LE_sx
echo
return "$LE_ret"
}
To be used as:
LE 'Prompt: '
Or:
LE 'Prompt: [....]\b\b\b\b\b' 4 . DEF
if you want a maximum length and/or different filling character and/or an initial value.
Best Answer
The
set
command in the readline manual is the one in readline's configuration file,~/.inputrc
. Although bash is the most famous user of the readline library, the library is generic and can be used by other programs; the syntax of.inputrc
is unrelated to bash.You can make bash execute readline commands through the
bind
builtin:Also, you can make bash reread
~/.inputrc
withbind -f ~/.inputrc
.