Я хочу считать строку текста и смочь переместить курсор, левый и правый при редактировании.
Когда я звоню cat
или используйте read
в ударе и клавишах со стрелками нажатия, я добираюсь ^[[A^[[B^[[C^[[D
istead перемещения курсора.
Я использую bash
от gnome-terminal
и mate-terminal
, локально (никакой SSH).
Благодаря @steeldriver я нашел решение, которое позволяет движущийся курсор слева/справа и не показывает историю удара при нажатии/стрелки вниз.
history -c # clear history
read -ep "$*" var # read value using readline,
# display prompt supplied as argument
echo "$var" # echo the value so it can be captured by the caller
Затем назовите этот сценарий из другого сценария или оболочки:
var=`readline 'value: '`
Эта функция может быть определена для выполнения в подоболочке, делая его по существу тем же как вышеупомянутый сценарий:
readline() (
history -c
read -ep "$*" var
echo "$var"
)
Или это может быть выполнено непосредственно в текущей оболочке, в этом случае история текущей оболочки должна быть сохранена до очистки его и затем восстановлена:
readline() {
history -w # write current history to the $HISTFILE
history -c # ...
read -ep "$*" var # ... same as above
echo "$var" # ...
history -r # resotre history (read from $HISTFILE)
}
Однако, если Вы решите нажать Ctrl+C при введении текста, то Вы закончите без истории, потому что функция будет прервана прежде, чем восстановить историю.
Решение состоит в том, чтобы использовать прерывания. Настройте прерывание на сигнале INT, который восстанавливает историю и затем "не захватывает" сигнал.
readline() {
# set up a trap which restores history and removes itself
trap "history -r; trap - SIGINT; return" SIGINT
history -w
history -c
read -ep "$*" var
echo "$var"
history -r
trap - SIGINT
}
Однако, если бы прерывание уже настраивается на сигнале INT, Вы просто отбросили бы его. Таким образом, необходимо сохранить уже существующее прерывание, затем настройте новый, ведите бизнес и затем восстановите старый.
readline() {
local err=0 sigint_trap orig_trap
sigint_trap=`trap -p | grep ' SIGINT$'`
if [[ $sigint_trap ]]; then
# A trap was already set up ‒ save it
orig_trap=`sed 's/trap -- \(.*\) SIGINT$/\1/' <<<"$sigint_trap"`
fi
# Don't do anything upon receiving SIGINT (eg. user pressed Ctrl+C).
# This is to prevent the function from exiting before it has restored
# the original trap.
trap ':' SIGINT
# `read` must be called from a subshell, otherwise it will run
# again and again when interrupted. This has something to do with
# the fact that `read` is a shell builtin. Since `read` reads a value
# into variable in a subshell, this variable won't exist in the parent
# shell. And since a subshell is already used, the history might as well
# be cleared in the subshell instead of the current shell ‒ then it's
# not necessary to save and restore it. If this subshell returns a
# non-zero value, the call to `read` was interrupted, and there will be
# no output. However, no output does not indicate an interrupted read,
# since the input could have been empty. That's why an exit code is
# necessary ‒ to determine whether the read was interrupted.
( history -c
read -ep "$*" var
echo "$var"
) || {
# `read` was interrupted ‒ save the exit code and echo a newline
# to stderr (because stdin is captured by the caller).
err=$?
echo >&2
}
# The subshell can be replaced by a call to the above script:
## "`which readline`" "$@" || { err=$?; echo >&2; }
if [[ $sigint_trap ]]; then
# Restore the old trap
trap "`eval echo "$orig_trap"`" SIGINT
else
# Remove trap
trap - SIGINT
fi
# Return non-zero if interrupted, else zero
return $err
}
Таким образом даже при том, что эта последняя версия "немного" более сложна, чем исходная и все еще не старается не запускать подоболочку, это обеспечивает признак того, было ли чтение успешно или не (который ни одна из более простых версий не делает).
Это может использоваться как так:
my_function() {
...
message=`readline $'\e[1mCommit message:\e[m '` || {
echo "[User abort]" >&2
return 1
}
...
}
С read
встроенный из эти bash
оболочка, можно использовать -e
опция включить поддержку readline. От help read
:
-e use Readline to obtain the line in an interactive shell
, Например
read -ep "Please enter some text: "
я не знаю ни о каком способе сделать это с cat
здесь-документ.